package com.bbcare.comm;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.imageio.ImageIO;
import javax.net.ssl.HttpsURLConnection;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import com.bbcare.sso.client.AccountService;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.Cell;
import org.dom4j.Attribute;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import redis.clients.jedis.Jedis;
import sun.misc.BASE64Encoder;

import com.aliyun.oss.ClientException;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sms.model.v20160927.SingleSendSmsRequest;
import com.aliyuncs.sms.model.v20160927.SingleSendSmsResponse;
import com.bbcare.sso.client.Account;
import com.bbcare.sso.client.AuthorizingFilter;
import com.bbcare.sso.client.Tenant;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
 * @name: 通用工具类
 * @author: DemonLee
 * @createTime: 2017.4.24
 * @description: 相关通用方法
 * @modify:
 *
 */

public class ToolUtils extends com.bbcare.comm.ToolUtil {
    private final static Log logger = LogFactory.getLog(ToolUtils.class);

    // redis关闭
    public static void closeRedis(Jedis jedis) {
        if (null != jedis) {
            try {
                jedis.close();
                logger.warn("close redis connection...");
            } catch (Exception ex) {
                ex.printStackTrace();
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_REDIS_CONNECT_CLOSE_FAILED, "Redis缓存关闭失败!"));
            }
        }
        return;
    }

    // 拼装redis-key
    public static String assembleKey(List<String> varList) {
        if (null == varList || 0 == varList.size()) {
            return null;
        }
        StringBuffer keyBuffer = new StringBuffer();
        int k = 0;
        for (k = 0; k < varList.size(); k++) {
            keyBuffer.append(varList.get(k));
            keyBuffer.append(Constants.COLON_SPLIT_STR);
        }
        return keyBuffer.substring(0, keyBuffer.length() - Constants.COLON_SPLIT_STR.length());
    }

    // 类型转换，去掉unchecked cast warning
    @SuppressWarnings("unchecked")
    public static <T> T typeCast(Object obj) {
        return (T) obj;
    }

    //Updated by Michael on 2022/6/28.
    public static Map<String, Object> getSessionInfo(HttpServletRequest request) {
        Map<String, Object> outRet = new HashMap<String, Object>();

        HttpSession session = request.getSession(true); //如果没有老session，就新建1个session。
        if (null == session) {
            //新session都没有。
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_SESSION_ISNULL, "session为空！"));
        }

        //从session中获取登录医生账号。
        Account account = (Account) session.getAttribute(AuthorizingFilter.SESSION_ACCOUNT_KEY);
        if (null == account || account.getRefTenantId() == null) {
            //session中没有账号。
            logger.warn("----getSessionInfo() account is NULL, so reload account info from REDIS.");
            final String sessionId = request.getParameter("sessionId"); //前端发送的sessionId参数值。
            logger.warn("----getSessionInfo() sessionId:"+sessionId);
            if (StringUtils.isEmpty(sessionId)) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_SESSION_VALUEISNULL, "获取sessionId为空！"));
            }
            //从redis中获取登录账户。
            account = AccountService.getInstance().getAccount(sessionId);
            if (null == account) {
                //无法从redis中获取登录账户（超时被移除了或者被人工移除了）。
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_SESSION_VALUEISNULL, "获取redis account为空！"));
            } else {
                //保存登录账户到session中。
                 session.setAttribute(AuthorizingFilter.SESSION_ACCOUNT_KEY, account);
            }
        }
        Tenant tenant = account.getTenant();
        if (null == tenant) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_SESSION_VALUEISNULL, "获取session租户值为空！"));
        }

        outRet.put("loginId", account.getUsername());
        outRet.put("authorName", account.getAlias());
        outRet.put("tenantId", tenant.getId());
        outRet.put("tenantName", tenant.getName());

        outRet.put("authorType", tenant.getType());
        outRet.put("authorId", account.getRelationId());

        // 租户类型：1、科室，2、医院，3、多中心，4、医联体
        outRet.put("groupType", tenant.getType());
        outRet.put("rootGroupId", tenant.getRootGroupId());
        outRet.put("refTenantId", account.getRefTenantId());
        if (Constants.TENANT_GROUP_TYPE_FOR_DEPT == tenant.getType()) {
            outRet.put("deptId", tenant.getRootGroupId());
        } else if (Constants.TENANT_GROUP_TYPE_FOR_HOSPITAL == tenant.getType()) {
            // TODO
        } else if (Constants.TENANT_GROUP_TYPE_FOR_MULCENTER == tenant.getType()) {
            // TODO
        } else if (Constants.TENANT_GROUP_TYPE_FOR_UNION == tenant.getType()) {
            // TODO
        }

        logger.warn("outRet==" + outRet.toString());

        return outRet;
    }

    public static String getPregnancyStr(int pregnancy) {
        StringBuilder builder = new StringBuilder();
        String week = String.valueOf(pregnancy / 7);
        String day = String.valueOf(pregnancy % 7);
        builder.append(week);
        builder.append("周");
        builder.append(day);
        builder.append("天");
        return builder.toString();
    }

    /**
     * 校验入参根节点、json格式以及业务data节点
     **/
    public static void checkInputRoot(String arg) {
        if (StringUtils.isBlank(arg)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR, "入参信息为空！"));
        }
        com.alibaba.fastjson.JSONObject jsonArg = null;
        try {
            jsonArg = com.alibaba.fastjson.JSON.parseObject(arg);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_FORMAT_ERROR,
                    Constants.API_INPUT_PARAMS_FORMAT_ERROR + "，非json格式！"));
        }

        Map<String, Object> mapIn = jsonArg.getJSONObject(Constants.INF_INPUTPARAM_COMMONFIELD);
        if (null == mapIn) {
            // 前台必须传data节点，否则报错返回
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，无data节点！"));
        }

        return;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持String类型为空校验
     **/
    public static void checkInputInfo(String checkNode, Map<String, Object> argInfo, Map<String, Object> checkVarInfo) {
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }

        String chkVarStr = "";
        String chkVarValue = "";
        Iterator<String> iter = checkVarInfo.keySet().iterator();
        while (iter.hasNext()) {
            chkVarStr = "";
            chkVarValue = "";
            chkVarStr = iter.next();
            chkVarValue = (String) checkVarInfo.get(chkVarStr);

            try {
                if (StringUtils.isBlank((String) argInfo.get(chkVarStr))) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                            Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarValue + "为空！"));
                }
            } catch (AppException e) {
                throw (e);
            } catch (Exception e) {
                List<Object> classIdList = ToolUtils.typeCast(argInfo.get(chkVarStr));// 文件id
                if (classIdList == null || classIdList.size() <= 0) {
                    throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                            Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarValue + "为空！"));
                }

            }

        }

        return;
    }

    /**
     * 校验入参中节点是否为空 checkNode: 校验的节点名称; argInfo: 校验入参源; checkVarInfo: 待校验的变量
     * 支持Integer类型为空及大于等于0校验
     **/
    public static void checkInputIntegerGe(String checkNode, Map<String, Object> argInfo,
            Map<String, Object> checkVarInfo) {
        if (MapUtils.isEmpty(checkVarInfo)) {
            return;
        }
        if (MapUtils.isEmpty(argInfo)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                    Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + checkNode + "节点为空！"));
        }

        String chkVarStr = "";
        String chkVarName = "";
        Integer chkVarValue = null;
        Iterator<String> iter = checkVarInfo.keySet().iterator();
        while (iter.hasNext()) {
            chkVarStr = "";
            chkVarName = "";
            chkVarStr = iter.next();
            chkVarName = (String) checkVarInfo.get(chkVarStr);

            chkVarValue = (Integer) argInfo.get(chkVarStr);
            if (null == chkVarValue || chkVarValue < 0) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        Constants.API_INPUT_PARAMS_DATA_ERROR + "，" + chkVarName + "为空或传值错误！"));
            }
        }

        return;
    }

    // 从问卷中解析用户基本信息
    public static Map<String, Object> parseUserInfoByQues(Map<String, Object> inPut) {
        Map<String, Object> inMap = new HashMap<String, Object>(inPut);
        Map<String, Object> outMap = new HashMap<String, Object>();
        // 手机号码
        String phoneNo = (String) inMap.get(Constants.QUESTION_ID_FOR_PHONENO);

        if (!StringUtils.isBlank(phoneNo)) {
            phoneNo = phoneNo.trim();
            outMap.put("phoneNo", phoneNo);
        }
        // 患者姓名
        String userName = (String) inMap.get(Constants.QUESTION_ID_FOR_PATIENTNAME);
        if (!StringUtils.isBlank(userName)) {
            userName = userName.trim();
            outMap.put("userName", userName);
            //更新名字拼音 2018-01-11
            try {
				outMap.put("namePinyin", ToolUtils.getEname(userName));
				outMap.put("nameInitial", ToolUtils.getNameInitial(userName));
			} catch (BadHanyuPinyinOutputFormatCombination e) {
				outMap.put("namePinyin","");
				outMap.put("nameInitial", "");
			}
            outMap.put("firstName", userName.substring(0, 1));
        }
        // 性别
        String gender = (String) inMap.get(Constants.QUESTION_ID_FOR_GENDER);
        if (!StringUtils.isBlank(gender)) {
            gender = gender.trim();
            // 转换性别
            if (Constants.GENDER_ALIAS_FOR_MALE.equals(gender) || gender.startsWith(Constants.GENDER_ALIAS_FOR_MALE)) {
                gender = Constants.GENDER_FOR_MALE;
            } else if (Constants.GENDER_ALIAS_FOR_FEMALE.equals(gender) || gender.startsWith(Constants.GENDER_ALIAS_FOR_FEMALE)) {
                gender = Constants.GENDER_FOR_FEMALE;
            } else if (!Constants.GENDER_FOR_MALE.equals(gender) && !Constants.GENDER_FOR_FEMALE.equals(gender)) {
                gender = Constants.GENDER_FOR_MALE;
            }
            outMap.put("gender", gender);
        }
        // 出生日期
        String birthday = (String) inMap.get(Constants.QUESTION_ID_FOR_BIRTHDAY);
        if (!StringUtils.isBlank(birthday)) {
            birthday = birthday.trim();
            outMap.put("birthday", birthday);
        }
        // 预产期
        String expectedDay = (String) inMap.get(Constants.QUESTION_ID_FOR_EXPECTEDDAY);
        if (!StringUtils.isBlank(expectedDay)) {
            expectedDay = expectedDay.trim();
            outMap.put("expectedDay", expectedDay);
        }

        String idCard = (String) inMap.get(Constants.QUESTION_ID_FOR_IDCARD);
        if (!StringUtils.isBlank(idCard)) {
            idCard = idCard.trim();
            outMap.put("idCard", idCard);
        }

        if (!StringUtils.isEmpty(birthday) && !StringUtils.isEmpty(expectedDay)) {
            // 根据生日和预产期计算孕周
            int pregnancyDay = calPrenDayByBirthAndExpect(birthday, expectedDay);
            outMap.put("pregnancyDay", pregnancyDay);
        }

        if (0 == outMap.size()) {
            return null;
        }
        return outMap;
    }

    // 按照任务触发方式，计算任务执行时间
    public static String getExecuteTime(Map<String, Object> pIn) {
        logger.warn("getExecuteTime pIn==" + pIn.toString());

        String currDay = (String) pIn.get("currDay");
        int iPrenDay = Integer.parseInt("" + pIn.get("prenDay"));
        String birthDay = (String) pIn.get("birthDay");
        String executeType = (String) pIn.get("executeType");
        int iTaskSeq = Integer.parseInt("" + pIn.get("taskSeq"));
        // int iCycleDay = Integer.parseInt("" + pIn.get("cycleDay"));
        int ageDay = Integer.parseInt("" + pIn.get("ageDay"));
        int executeDay = Integer.parseInt("" + pIn.get("executeDay"));
        // 建档问卷填写内容
        Map<String, Object> inputContData = typeCast(pIn.get("inputContData"));
        String executeTime = "";
        if (0 == iTaskSeq) {
            executeTime = currDay;
        }

        if (Constants.SCHEME_TASK_EXECUTE_TYPE_0.equals(executeType)) {
            // 0：应用后触发（当天建档+第一次随访，然后按周期进行第n次随访）
            if (1 == iTaskSeq) {
                executeTime = currDay;
            } else if (iTaskSeq >= 2) {
                executeTime = DateUtil.calcDay(currDay, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_1.equals(executeType)) {
            // 1：纠正年龄触发（37周以下用纠正年龄(2岁内)，其他用出生年龄）
            if (iTaskSeq >= 1) {
                if (ageDay <= (2 * 365) && iPrenDay < Constants.PATIENT_PREMATURE_PREGNANT_DAY) {
                    executeTime = DateUtil.calcDay(birthDay, "+",
                            (Constants.PATIENT_NORMAL_PREGNANT_DAY - iPrenDay) + executeDay);
                } else {
                    executeTime = DateUtil.calcDay(birthDay, "+", executeDay);
                }
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_2.equals(executeType)) {
            // 2：出生年龄触发（当天建档，后续随访日期按出生日期+周期计算）
            if (iTaskSeq >= 1) {
                executeTime = DateUtil.calcDay(birthDay, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_3.equals(executeType)) {
            // 3：出院后触发（出院日建档，后续随访按照出院日期+周期计算）
            String outHospitalDay = (String) pIn.get("outHospitalDay");
            if (StringUtils.isEmpty(outHospitalDay)) {
                // 从问卷答案中再找一遍
                if (MapUtils.isNotEmpty(inputContData)) {
                    outHospitalDay = (String) inputContData.get(Constants.QUESTION_ID_FOR_LEAVEHOSPITAL_DATE);
                }
                if (StringUtils.isEmpty(outHospitalDay)) {
                    throw new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_TASKEXECUTETYPE_OUTHOSPITAL_PARAM,
                            "出院后触发随访任务需要填写出院日期！");
                }
            }
            if (iTaskSeq >= 1) {
                executeTime = DateUtil.calcDay(outHospitalDay, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_4.equals(executeType)) {
            // 4：初检孕周日期触发（孕产妇随访，初次孕检日建档）
            Integer firstChkPregWeek = (Integer) pIn.get("firstChkPregWeek");
            if (null == firstChkPregWeek || firstChkPregWeek <= 0) {
                throw new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        "随访计划按初检孕周触发，初检孕周不能为空！");
            }
            if (0 == iTaskSeq) {
                executeTime = currDay;
            } else {
                int dealDay = executeDay - firstChkPregWeek * 7;
                if (dealDay <= 0) {
                    dealDay = 0;
                }
                executeTime = DateUtil.calcDay(currDay, "+", dealDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_5.equals(executeType)) {
            // 5：末次月经日期触发（孕产妇随访）
            String lastMenstruationDate = (String) pIn.get("lastMenstruationDate");
            if (StringUtils.isBlank(lastMenstruationDate)) {
                throw new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        "随访计划按末次月经日期触发，末次月经日期不能为空！");
            }
            if (0 == iTaskSeq) {
                executeTime = currDay;
            } else {
                executeTime = DateUtil.calcDay(lastMenstruationDate, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_6.equals(executeType)) {
            // 6：应用后触发（当天建档，然后按周期进行第n次随访）
            if (iTaskSeq >= 1) {
                executeTime = DateUtil.calcDay(currDay, "+", executeDay);
            }
        } else if (Constants.SCHEME_TASK_EXECUTE_TYPE_7.equals(executeType)) {
            // 7：分娩日期触发（孕产妇产后随访）
            String deliveryDate = (String) pIn.get("deliveryDate");
            if (StringUtils.isBlank(deliveryDate)) {
                throw new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR,
                        "随访计划按分娩日期触发，分娩日期不能为空！");
            }
            if (0 == iTaskSeq) {
                executeTime = currDay;
            } else {
                executeTime = DateUtil.calcDay(deliveryDate, "+", executeDay);
            }
        } else {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_TASKEXECUTETYPE_UNKNOWN, "任务触发方式未定义！"));
        }

        // 如果有首次随访日期，则第1次随访使用首次随访日期
        if (MapUtils.isNotEmpty(inputContData)) {
            String firstFollowDate = (String) inputContData.get(Constants.QUESTION_ID_FOR_FIRST_FOLLOW_DATE);
            if (StringUtils.isNotBlank(firstFollowDate) && 1 == iTaskSeq) {
                executeTime = firstFollowDate;
            }
        }

        return executeTime;
    }

    // 根据任务规则，计算开始结束时间
    public static Map<String, Object> getTaskRuleTime(Map<String, Object> pIn) {
        Map<String, Object> outMap = new HashMap<String, Object>();

        // String currDay = (String) pIn.get("currDay");
        int iPrenDay = Integer.parseInt("" + pIn.get("prenDay"));
        String birthDay = (String) pIn.get("birthday");
        String ruleType = (String) pIn.get("ruleType");
        int beginDay = Integer.parseInt("" + pIn.get("beginDay"));
        int endDay = Integer.parseInt("" + pIn.get("endDay"));
        int ageDay = Integer.parseInt("" + pIn.get("ageDay"));
        String beginDate = "";
        String endDate = "";

        // 纠正月龄
        if (Constants.TASK_TYPE_SCHEME_SELFREPORT_MONTHAGE.equals(ruleType)) {
            if (ageDay <= (2 * 365) && iPrenDay < Constants.PATIENT_PREMATURE_PREGNANT_DAY) {
                beginDate = DateUtil.calcDay(birthDay, "+",
                        (Constants.PATIENT_NORMAL_PREGNANT_DAY - iPrenDay) + beginDay);
                endDate = DateUtil.calcDay(birthDay, "+", (Constants.PATIENT_NORMAL_PREGNANT_DAY - iPrenDay) + endDay);
            } else {
                beginDate = DateUtil.calcDay(birthDay, "+", beginDay);
                endDate = DateUtil.calcDay(birthDay, "+", endDay);
            }
        } else {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_TASKEXECUTETYPE_UNKNOWN, "任务触发方式未定义！"));
        }
        outMap.put("beginDate", beginDate);
        outMap.put("endDate", endDate);

        return outMap;
    }

    // 根据出生日期和预产期计算孕周，返回天数
    public static int calPrenDayByBirthAndExpect(String birthday, String expectedDay) {
        int day = 0;
        if (!StringUtils.isEmpty(birthday) && !StringUtils.isEmpty(expectedDay)) {
            try {
                Date birthdayDate = DateUtil.getDate_8(birthday);
                Date expectedDate = DateUtil.getDate_8(expectedDay);

                Calendar exp = Calendar.getInstance();
                Calendar bir = Calendar.getInstance();
                exp.setTime(expectedDate);
                bir.setTime(birthdayDate);
                long expTime = exp.getTimeInMillis();
                long birTime = bir.getTimeInMillis();
                long bet = birTime - expTime;
                day = Constants.PATIENT_NORMAL_PREGNANT_DAY + (int) (bet / 86400000L);
                // 后续考虑最小孕周和最大孕周的情况，加校验，这里先只校验小于0的情况
                if (day < 0) {
                    day = 0;
                }
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
            }
        }
        return day;
    }

    // 根据生日计算年龄，返回天数
    public static int getBirthAgeDay(String birthday) {
        int day = 0;
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            long bet = now.getTimeInMillis() - cal.getTimeInMillis();
            if (bet < 0L) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_BIRTHDAY_EXPEND_NOW, "时间计算错误，出生日期大于当前时间！"));
            }
            day = (int) (bet / 86400000L);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
        }
        return day;
    }

    // 两个日期时间，返回天
    public static int getBirthAgeByTwoStrDate(String beginDateStr, String endDateStr) {
        int day = 0;
        try {
            Date beginDate = DateUtil.getDate_8(beginDateStr);
            Date endDate = DateUtil.getDate_8(endDateStr);
            Calendar end = Calendar.getInstance();
            Calendar begin = Calendar.getInstance();
            end.setTime(endDate);
            begin.setTime(beginDate);
            long bet = end.getTimeInMillis() - begin.getTimeInMillis();
            if (bet < 0L) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_BIRTHDAY_EXPEND_NOW, "时间计算错误，出生日期大于当前时间！"));
            }
            day = (int) (bet / 86400000L);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
        }
        return day;
    }

    // 根据生日计算年龄，返回天数
    public static String getBirthAgeWeek(String birthday) {
        int day = 0;
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            long bet = now.getTimeInMillis() - cal.getTimeInMillis();
            if (bet < 0L) {
                throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_BIRTHDAY_EXPEND_NOW, "时间计算错误，出生日期大于当前时间！"));
            }
            day = (int) (bet / 86400000L);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
        }
        return day / 7 + "周";
    }

    // 根据生日和当前时间计算年龄
    public static String getAgeByDate(String birthday, Date currentDate) throws ParseException {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        now.setTime(currentDate);

        Calendar cal = Calendar.getInstance();
        // int age = 0;
        if (!cal.before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。
            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            int week = 0;
            // 暂时展示 一个单位 岁、或月、周、天

            if (year > 0) {
                builder.append(year).append("岁");
            }

            if (month > 0 && year >= 0) {
                builder.append(month).append("月");
            } else if (day > 0 && month >= 0 && year >= 0) {
                if (day > 7) {// 展示周
                    week = day / 7;
                    builder.append(week).append("周");
                } else {
                    builder.append(day).append("天");
                }
            } else {
                builder.append("0").append("天");
            }
        } else {
            builder.append("0").append("天");
        }
        return builder.toString();
    }

    // 根据生日和当前时间计算年龄2
    public static String getAgeMonDayByDate(String birthday, String DateStr) throws ParseException {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        Calendar cal = Calendar.getInstance();
        if (StringUtils.isBlank(birthday) || StringUtils.isBlank(DateStr)) {
            // 入参为空，则返回空
            return null;
        }
        now.setTime(DateUtil.getDate_8(DateStr));
        if (!now.getTime().before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。
            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            // 暂时展示 一个单位 岁、或月、天
            if (year > 0) {
                builder.append(year).append("岁");
            }
            if (month > 0 && year >= 0) {
                builder.append(month).append("月龄");
            }
            if (day > 0 && month >= 0 && year >= 0) {
                builder.append(day).append("天");
            } else {
                builder.append("0").append("天");
            }
        } else {
            builder.append("0").append("天");
        }
        return builder.toString();
    }

    // 根据生日和当前时间计算年龄3
    /**
     * 1、小于三个月的显示几周几天，(days<3*30)
     * 2、小于1岁的显示几月龄几天，  (3*30<=days<1*365)
     * 3、大于一岁的显示几岁几月龄，(1*365<=days<6*365)
     * 4、大于六岁的只显示岁。     (days>=6*365)
     */
    public static String getAgeMonDayByDate3(String birthday, String DateStr) throws ParseException {
        if (StringUtils.isBlank(birthday) || StringUtils.isBlank(DateStr)) {
            // 入参为空，则返回空
            return null;
        }
        if (birthday.compareTo(DateStr) > 0) {
            return null;
        }
        int days = getBirthAgeByTwoStrDate(birthday, DateStr);
        if (days <= 0) {
            return null;
        }
        String age = "";
        if (days < 3 * Constants.MONTH_DAY) {
            int week = days / Constants.PREGNANCY_CALC_UNIT_WEEK;
            int day = days % Constants.PREGNANCY_CALC_UNIT_WEEK;
            if (week != 0) {
                age += week + "周";
            }
            age += day + "天";
        } else if (days < 1 * Constants.YEAR_DAY) {
            int month = days / Constants.MONTH_DAY;
            int day = days % Constants.MONTH_DAY;
            if (month != 0) {
                age += month + "月龄";
            }
            if (day != 0) {
                age += day + "天";
            }
        } else if (days < 6 * Constants.YEAR_DAY) {
            int year = days / Constants.YEAR_DAY;
            int month = (days % Constants.YEAR_DAY) / Constants.MONTH_DAY;
            if (year != 0) {
                age += year + "岁";
            }
            if (month != 0) {
                age += month + "月龄";
            }
        } else {
            int year = days / Constants.YEAR_DAY;
            if (year != 0) {
                age += year + "岁";
            }
        }

        return age;
    }

    // 根据生日计算年龄
    public static String getAgeMonDayByBirthday(String birthday) throws ParseException {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        Calendar cal = Calendar.getInstance();
        if (StringUtils.isEmpty(birthday)) {// 如果没有生日 则返回空
            return null;
        }
        // int age = 0;
        if (!now.getTime().before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。
            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            // 暂时展示 一个单位 岁、或月、天
            if (year > 0) {
                builder.append(year).append("岁");
            }
            if (month > 0 && year >= 0) {
                builder.append(month).append("月龄");
            }
            if (day > 0 && month >= 0 && year >= 0) {
                builder.append(day).append("天");
            } else {
                builder.append("0").append("天");
            }
        } else {
            builder.append("0").append("天");
        }
        return builder.toString();
    }

    // 根据生日计算年龄
    public static String getAgeByBirthday(String birthday) throws ParseException {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        Calendar cal = Calendar.getInstance();
        // int age = 0;
        if (!now.getTime().before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            int week = 0;
            // 暂时展示 一个单位 岁、或月、周、天

            if (year > 0) {
                builder.append(year).append("岁");
            }

            if (month > 0 && year >= 0) {
                builder.append(month).append("个月");
            } else if (day > 0 && month >= 0 && year >= 0) {
                if (day > 7) {// 展示周
                    week = day / 7;
                    builder.append(week).append("周");
                } else {
                    builder.append(day).append("天");
                }
            } else {
                builder.append("0").append("天");
            }
        } else {
            builder.append("0").append("天");
        }
        return builder.toString();
    }

    // 矫正年龄
    public static Long getCorrect(String birthday, Integer pregnancyWeek) {
        // TODO Auto-generated method stub
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Long time = new Date().getTime();
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            int year = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
            int day = now.get(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH);
            int month = now.get(Calendar.MONTH) - cal.get(Calendar.MONTH);

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }
            if (null == pregnancyWeek || 0 == pregnancyWeek || pregnancyWeek >= 259
                    || (year >= 2 && month >= 0 && day >= 0)) { // 孕周大于37
                // 或者
                // 大于2岁
                // 按正常年龄算
                time = birthdayDate.getTime();
            } else {
                time = birthdayDate.getTime() + (280 - pregnancyWeek) * 86400000L;
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return time;
    }

    // 检测日期对应的矫正年龄
    public static Long getCorrectCheckAge(Map<String, Object> mapIn) {
        String birthday = (String) mapIn.get("birthday");
        Integer pregnancyWeek = (Integer) mapIn.get("pregnancyDay");
        String checkDate = (String) mapIn.get("checkDate");
        Long time = new Date().getTime();
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            now.setTime(DateUtil.getDate_8(checkDate));

            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            int year = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
            int day = now.get(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH);
            int month = now.get(Calendar.MONTH) - cal.get(Calendar.MONTH);

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }
            if (null == pregnancyWeek || 0 == pregnancyWeek || pregnancyWeek >= 259
                    || (year >= 2 && month >= 0 && day >= 0)) { // 孕周大于37
                // 或者
                // 大于2岁
                // 按正常年龄算
                time = birthdayDate.getTime();
            } else {
                time = birthdayDate.getTime() + (280 - pregnancyWeek) * 86400000L;
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        return time;
    }

    // 根据生日和业务类型，返回月龄（实际年龄）
    public static String getMonthAgeByBirthAndType(Map<String, Object> mapIn) {
        String birthday = (String) mapIn.get("birthday");
        if (StringUtils.isBlank(birthday)) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_INPUT_DATA_VERIFY_ERROR, "时间计算错误，出生日期传值为空！"));
        }
        String finishDate = (String) mapIn.get("finishDate");
        Integer type = (Integer) mapIn.get("type");
        if (null == type) {
            type = 0;
        }
        // 检测日期对应的年龄
        int day = getBirthAgeByTwoStrDate(birthday, finishDate);
        String month = "";
        if (day > 0) {
            double iMonDeci = (double) day / 30;// 精确小数位
            int iMonInt = day / 30;// 整数
            switch (type) {
            case 1: {
                // 身高
                if (iMonInt >= 12 && iMonInt <= 81) {
                    // 12-14用12月的标准
                    iMonInt = (iMonInt / 3) * 3;
                }
                break;
            }
            case 2: {
                // 体重
                if (iMonInt >= 12 && iMonInt <= 81) {
                    // 12-14用12月的标准
                    iMonInt = (iMonInt / 3) * 3;
                }
                break;
            }
            case 3: {
                // 腰围
                break;
            }
            case 4: {
                // 胸围
                if (7 == iMonInt) {
                    iMonInt = 6;
                } else if (9 == iMonInt) {
                    iMonInt = 8;
                } else if (11 == iMonInt) {
                    iMonInt = 10;
                } else if (iMonInt >= 12 && iMonInt < 78) {
                    // 12-17用12月的标准
                    iMonInt = (iMonInt / 6) * 6;
                }
                break;
            }
            case 5: {
                // 舒张压
                iMonInt = getBloodPressureMonth(iMonDeci);
                break;
            }
            case 6: {
                // 收缩压
                iMonInt = getBloodPressureMonth(iMonDeci);
                break;
            }
            case 7: {
                // 上臀部皮褶厚度
                break;
            }
            case 8: {
                // 肩胛部皮褶厚度
                break;
            }
            case 9: {
                // 腰部皮褶厚度
                break;
            }
            case 10: {
                // 上臂围
                break;
            }
            case 11: {
                // 骨骼肌
                iMonInt = day;
                break;
            }
            case 12: {
                // 体脂百分比
                break;
            }
            case 13: {
                // 体脂肪
                iMonInt = day;
                break;
            }
            }
            month = "" + iMonInt;
        }

        return month;
    }

    // 血压标准数据的月份
    public static int getBloodPressureMonth(double iMonDeci) {
        int iMonInt = (int) iMonDeci;
        if (iMonDeci < 1) {
            iMonInt = 0;
        } else if (iMonDeci >= 1 && iMonDeci < 7) {
            iMonInt = 1;
        } else if (iMonDeci >= 7 && iMonDeci < 12) {
            iMonInt = 7;
        } else if (iMonDeci >= 12) {
            iMonInt = (iMonInt / 12) * 12;
        }

        return iMonInt;
    }

    // 身高体重--标准数据
    public static Map<String, Object> getHeightWeightData(Map<String, Object> mapIn) {
        // 调该函数之前，入参都已经做过校验
        Map<String, Object> mapOut = null;
        String templData = (String) mapIn.get("templData");
        Map<String, Object> jsonMap = com.alibaba.fastjson.JSON.parseObject(templData);
        String value = (String) mapIn.get("value");
        String key = (String) mapIn.get("key");
        String gender = (String) mapIn.get("gender");
        Map<String, Object> genderMap = typeCast(jsonMap.get(gender));
        if (MapUtils.isNotEmpty(genderMap)) {
            Map<String, Object> dataMap = typeCast(genderMap.get(key));
            if (MapUtils.isNotEmpty(dataMap)) {
                Object negativeObj = dataMap.get("negative2");
                Object positiveObj = dataMap.get("positive2");
                if (null != negativeObj && null != positiveObj) {
                    Double negative2 = Double.parseDouble(negativeObj.toString());
                    Double positive2 = Double.parseDouble(positiveObj.toString());
                    if (null != negative2 && null != positive2) {
                        List<Object> checkStandardList = new ArrayList<Object>();
                        checkStandardList.add("" + negative2);
                        checkStandardList.add("" + positive2);

                        int indexFlag = 0;
                        mapOut = new HashMap<String, Object>();
                        mapOut.put("indexFlag", 0);
                        mapOut.put("checkStandard", checkStandardList);
                        if (StringUtils.isNotBlank(value)) {
                            double num = 0.0;
                            try {
                                num = Double.parseDouble(value);
                            } catch (Exception e) {
                                // 非数字
                                e.printStackTrace();
                                return mapOut;
                            }
                            if (num < negative2) {
                                indexFlag = -1;
                            } else if (num > positive2) {
                                indexFlag = 1;
                            }
                            mapOut.put("indexFlag", indexFlag);
                        }
                    }
                }
            }
        }

        return mapOut;
    }

    // 腰围数据: 男：身高×43%±3 女：身高×47%±3（单位：cm）
    public static Map<String, Object> getWaistData(Map<String, Object> mapIn) {
        String value = (String) mapIn.get("value");
        String extendValue = (String) mapIn.get("extendValue");
        String gender = (String) mapIn.get("gender");
        Map<String, Object> mapOut = new HashMap<String, Object>();
        double iVal = 0.0;
        double iExtVal = 0.0;
        try {
            iVal = Double.parseDouble(value);
            iExtVal = Double.parseDouble(extendValue);
        } catch (Exception e) {
            // 非数字
            e.printStackTrace();
            return null;
        }
        int indexFlag = 0;
        // 保留两位小数
        double index = 0.0;
        if (Constants.GENDER_FOR_MALE.equals(gender)) {
            index = Constants.PHYSICAL_TYPE_FOR_M_WAIST_MULTI_INDEX;
        } else {
            index = Constants.PHYSICAL_TYPE_FOR_F_WAIST_MULTI_INDEX;
        }
        double minVal = iExtVal * index - Constants.PHYSICAL_TYPE_FOR_WAIST_RANGE_INDEX;
        double maxVal = iExtVal * index + Constants.PHYSICAL_TYPE_FOR_WAIST_RANGE_INDEX;
        if (minVal < 0) {
            minVal = 0;
        }
        if (iVal < minVal) {
            indexFlag = -1;
        } else if (iVal > maxVal) {
            indexFlag = 1;
        }
        List<Object> checkStandardList = new ArrayList<Object>();
        checkStandardList.add(String.format("%.2f", minVal));
        checkStandardList.add(String.format("%.2f", maxVal));
        mapOut.put("indexFlag", indexFlag);
        mapOut.put("checkStandard", checkStandardList);

        return mapOut;
    }

    // 胸围--标准数据
    public static Map<String, Object> getChestData(Map<String, Object> mapIn) {
        // 调该函数之前，入参都已经做过校验
        Map<String, Object> mapOut = null;
        String templData = (String) mapIn.get("templData");
        Map<String, Object> jsonMap = com.alibaba.fastjson.JSON.parseObject(templData);
        String value = (String) mapIn.get("value");
        String key = (String) mapIn.get("key");
        String gender = (String) mapIn.get("gender");
        Map<String, Object> genderMap = typeCast(jsonMap.get(gender));
        if (MapUtils.isNotEmpty(genderMap)) {
            Map<String, Object> dataMap = typeCast(genderMap.get(key));
            if (MapUtils.isNotEmpty(dataMap)) {
                Object negativeObj = dataMap.get("negative1");
                Object positiveObj = dataMap.get("positive1");
                if (null != negativeObj && null != positiveObj) {
                    Double negative1 = Double.parseDouble(negativeObj.toString());
                    Double positive1 = Double.parseDouble(positiveObj.toString());
                    if (null != negative1 && null != positive1) {
                        List<Object> checkStandardList = new ArrayList<Object>();
                        checkStandardList.add("" + negative1);
                        checkStandardList.add("" + positive1);

                        int indexFlag = 0;
                        mapOut = new HashMap<String, Object>();
                        mapOut.put("indexFlag", 0);
                        mapOut.put("checkStandard", checkStandardList);
                        if (StringUtils.isNotBlank(value)) {
                            double num = 0.0;
                            try {
                                num = Double.parseDouble(value);
                            } catch (Exception e) {
                                // 非数字
                                e.printStackTrace();
                                return mapOut;
                            }
                            if (num < negative1) {
                                indexFlag = -1;
                            } else if (num > positive1) {
                                indexFlag = 1;
                            }
                            mapOut.put("indexFlag", indexFlag);
                        }
                    }
                }
            }
        }

        return mapOut;
    }

    // 血压--标准数据
    public static Map<String, Object> getBloodPressureData(Map<String, Object> mapIn) {
        // 调该函数之前，入参都已经做过校验
        Map<String, Object> mapOut = null;
        String templData = (String) mapIn.get("templData");
        Map<String, Object> jsonMap = com.alibaba.fastjson.JSON.parseObject(templData);
        String value = (String) mapIn.get("value");
        String key = (String) mapIn.get("key");
        String bloodType = (String) mapIn.get("bloodType");// 收缩压或舒张压
        Map<String, Object> genderMap = typeCast(jsonMap.get(bloodType));
        if (MapUtils.isNotEmpty(genderMap)) {
            Map<String, Object> dataMap = typeCast(genderMap.get(key));
            if (MapUtils.isNotEmpty(dataMap)) {
                Object negativeObj = dataMap.get("negative1");
                Object positiveObj = dataMap.get("positive1");
                if (null != negativeObj && null != positiveObj) {
                    Integer negative1 = Integer.parseInt(negativeObj.toString());
                    Integer positive1 = Integer.parseInt(positiveObj.toString());

                    if (null != negative1 && null != positive1) {
                        List<Object> chkList = new ArrayList<Object>();
                        chkList.add("" + dataMap.get("negative2"));
                        chkList.add("" + negativeObj);
                        chkList.add("" + positiveObj);
                        chkList.add("" + dataMap.get("positive2"));

                        int indexFlag = 0;
                        mapOut = new HashMap<String, Object>();
                        mapOut.put("indexFlag", 0);
                        mapOut.put("checkStandard", chkList);
                        if (StringUtils.isNotBlank(value)) {
                            Double num = 0.0;
                            try {
                                num = Double.parseDouble(value);
                            } catch (Exception e) {
                                // 非数字
                                e.printStackTrace();
                                return mapOut;
                            }
                            if (num < negative1) {
                                indexFlag = -1;
                            } else if (num > positive1) {
                                indexFlag = 1;
                            }
                            mapOut.put("indexFlag", indexFlag);
                        }
                    }
                }
            }
        }

        return mapOut;
    }

    // 腹部皮褶厚度--标准数据：>=8mm
    public static Map<String, Object> getWaistSkinData(Map<String, Object> mapIn) {
        // 调该函数之前，入参都已经做过校验
        String value = (String) mapIn.get("value");
        Map<String, Object> mapOut = new HashMap<String, Object>();
        List<Object> checkStandardList = new ArrayList<Object>();
        checkStandardList.add(">=" + Constants.PHYSICAL_TYPE_FOR_WAISTSKINTHICK_THRESHOLD);
        mapOut.put("indexFlag", 0);
        mapOut.put("checkStandard", checkStandardList);
        if (StringUtils.isBlank(value)) {
            return mapOut;
        }
        double num = 0.0;
        try {
            num = Double.parseDouble(value);
        } catch (Exception e) {
            // 非数字
            e.printStackTrace();
            return mapOut;
        }
        int indexFlag = 0;
        if (num < Constants.PHYSICAL_TYPE_FOR_WAISTSKINTHICK_THRESHOLD) {
            indexFlag = -1;
        }
        mapOut.put("indexFlag", indexFlag);

        return mapOut;
    }

    // 上臂围--标准数据：1-5岁 >=12.5 （<12.5cm营养不良， 12.5~13.5cm 营养中等，>=13.5cm营养良好）
    public static Map<String, Object> getUpArmLenData(Map<String, Object> mapIn) {
        // 调该函数之前，入参都已经做过校验
        String key = (String) mapIn.get("key");
        String value = (String) mapIn.get("value");
        Map<String, Object> mapOut = new HashMap<String, Object>();
        List<Object> checkStandardList = new ArrayList<Object>();
        mapOut.put("indexFlag", 0);
        mapOut.put("checkStandard", checkStandardList);

        int ageMonth = 0;
        try {
            ageMonth = Integer.parseInt(key);
        } catch (Exception e) {
            // 非数字
            e.printStackTrace();
            return mapOut;
        }
        if (ageMonth >= 12 && ageMonth <= 60) {
            checkStandardList.add("" + Constants.PHYSICAL_TYPE_FOR_UPARMLEN_THRESHOLD);
            checkStandardList.add("" + Constants.PHYSICAL_TYPE_FOR_UPARMLEN_FINE);
            mapOut.put("checkStandard", checkStandardList);
        }
        if (StringUtils.isBlank(value)) {
            return mapOut;
        }

        double num = 0.0;
        try {
            num = Double.parseDouble(value);
        } catch (Exception e) {
            // 非数字
            e.printStackTrace();
            return mapOut;
        }
        int indexFlag = 0;
        if (ageMonth >= 12 && ageMonth <= 60) {
            if (num < Constants.PHYSICAL_TYPE_FOR_UPARMLEN_THRESHOLD) {
                indexFlag = -1;
            } else if (num > Constants.PHYSICAL_TYPE_FOR_UPARMLEN_FINE) {
                indexFlag = 1;
            }
        }
        mapOut.put("indexFlag", indexFlag);

        return mapOut;
    }

    // 骨骼肌--标准数据：男：47% x 标准体重（WHO2013） 区间：90%~110%； 女：42% x 标准体重 区间：90%-110%
    public static Map<String, Object> getSkeletalMuscleData(Map<String, Object> mapIn) {
        // 调该函数之前，入参都已经做过校验
        Map<String, Object> mapOut = null;
        Double weightBalance = (Double) mapIn.get("weightBalance");
        String value = (String) mapIn.get("value");
        String gender = (String) mapIn.get("gender");

        List<Object> checkStandardList = new ArrayList<Object>();
        double index = 0.0;
        if (Constants.GENDER_FOR_MALE.equals(gender)) {
            index = Constants.PHYSICAL_TYPE_FOR_SKELETAL_M_INDEX;
        } else {
            index = Constants.PHYSICAL_TYPE_FOR_SKELETAL_F_INDEX;
        }
        double minValue = weightBalance * index * Constants.PHYSICAL_TYPE_FOR_SKELETAL_INTERVAL_MIN;
        double maxValue = weightBalance * index * Constants.PHYSICAL_TYPE_FOR_SKELETAL_INTERVAL_MAX;
        checkStandardList.add(String.format("%.2f", minValue));
        checkStandardList.add(String.format("%.2f", maxValue));

        int indexFlag = 0;
        mapOut = new HashMap<String, Object>();
        mapOut.put("indexFlag", 0);
        mapOut.put("checkStandard", checkStandardList);
        if (StringUtils.isNotBlank(value)) {
            double num = 0.0;
            try {
                num = Double.parseDouble(value);
            } catch (Exception e) {
                // 非数字
                e.printStackTrace();
                return mapOut;
            }
            if (num < minValue) {
                indexFlag = -1;
            } else if (num > maxValue) {
                indexFlag = 1;
            }
            mapOut.put("indexFlag", indexFlag);
        }

        return mapOut;
    }

    // 体脂百分比--标准数据：男11%-21% 女18%-25%
    public static Map<String, Object> getBodyFatPercentData(Map<String, Object> mapIn) {
        // 调该函数之前，入参都已经做过校验
        String value = (String) mapIn.get("value");
        String gender = (String) mapIn.get("gender");
        Map<String, Object> mapOut = new HashMap<String, Object>();
        mapOut.put("indexFlag", 0);

        List<Object> checkStandardList = new ArrayList<Object>();
        if (Constants.GENDER_FOR_MALE.equals(gender)) {
            checkStandardList.add("" + Constants.PHYSICAL_TYPE_FOR_M_BODYFATPERCENT_MIN);
            checkStandardList.add("" + Constants.PHYSICAL_TYPE_FOR_M_BODYFATPERCENT_MAX);
        } else {
            checkStandardList.add("" + Constants.PHYSICAL_TYPE_FOR_F_BODYFATPERCENT_MIN);
            checkStandardList.add("" + Constants.PHYSICAL_TYPE_FOR_F_BODYFATPERCENT_MAX);
        }
        mapOut.put("checkStandard", checkStandardList);
        if (StringUtils.isBlank(value)) {
            return mapOut;
        }

        double num = 0.0;
        try {
            num = Double.parseDouble(value);
        } catch (Exception e) {
            // 非数字
            e.printStackTrace();
            return mapOut;
        }
        int indexFlag = 0;
        if (Constants.GENDER_FOR_MALE.equals(gender)) {
            if (num < Constants.PHYSICAL_TYPE_FOR_M_BODYFATPERCENT_MIN) {
                indexFlag = -1;
            } else if (num > Constants.PHYSICAL_TYPE_FOR_M_BODYFATPERCENT_MAX) {
                indexFlag = 1;
            }
        } else {
            if (num < Constants.PHYSICAL_TYPE_FOR_F_BODYFATPERCENT_MIN) {
                indexFlag = -1;
            } else if (num > Constants.PHYSICAL_TYPE_FOR_F_BODYFATPERCENT_MAX) {
                indexFlag = 1;
            }
        }
        mapOut.put("indexFlag", indexFlag);

        return mapOut;
    }

    // 体脂肪--标准数据：理想体重（即中位数）× 理想体脂百分比，理想体重来自WHO2013--体重百分位
    public static Map<String, Object> getBodyFatData(Map<String, Object> mapIn) {
        // 调该函数之前，入参都已经做过校验
        Map<String, Object> mapOut = null;
        Double weightBalance = (Double) mapIn.get("weightBalance");
        String value = (String) mapIn.get("value");
        String gender = (String) mapIn.get("gender");
        List<Object> checkStandardList = new ArrayList<Object>();
        double minValueIndex = 0.0;
        double maxValueIndex = 0.0;
        if (Constants.GENDER_FOR_MALE.equals(gender)) {
            minValueIndex = Constants.PHYSICAL_TYPE_FOR_M_BODYFATPERCENT_MIN;
            maxValueIndex = Constants.PHYSICAL_TYPE_FOR_M_BODYFATPERCENT_MAX;
        } else {
            minValueIndex = Constants.PHYSICAL_TYPE_FOR_F_BODYFATPERCENT_MIN;
            maxValueIndex = Constants.PHYSICAL_TYPE_FOR_F_BODYFATPERCENT_MAX;
        }
        double minValue = weightBalance * minValueIndex / 100;
        double maxValue = weightBalance * maxValueIndex / 100;
        checkStandardList.add(String.format("%.2f", minValue));
        checkStandardList.add(String.format("%.2f", maxValue));

        int indexFlag = 0;
        mapOut = new HashMap<String, Object>();
        mapOut.put("indexFlag", 0);
        mapOut.put("checkStandard", checkStandardList);
        if (StringUtils.isNotBlank(value)) {
            double num = 0.0;
            try {
                num = Double.parseDouble(value);
            } catch (Exception e) {
                // 非数字
                e.printStackTrace();
                return mapOut;
            }
            if (num < minValue) {
                indexFlag = -1;
            } else if (num > maxValue) {
                indexFlag = 1;
            }
            mapOut.put("indexFlag", indexFlag);
        }

        return mapOut;
    }

    // 获取体检登记标准数据并进行比较
    public static Map<String, Object> getPsyChkData(Map<String, Object> argMap) {
        logger.debug("---in getPsyChkData...arg==" + argMap);
        Map<String, Object> mapIn = new HashMap<String, Object>(argMap);
        Map<String, Object> mapOut = new HashMap<String, Object>();
        Map<String, Object> jsonMap = null;
        String templData = (String) mapIn.get("templData");
        if (StringUtils.isNotBlank(templData)) {
            jsonMap = com.alibaba.fastjson.JSON.parseObject(templData);
        }
        Integer type = (Integer) mapIn.get("type");
        if (null == type) {
            return null;
        }
        String value = (String) mapIn.get("value");
        String key = (String) mapIn.get("key");
        if (StringUtils.isBlank(key)) {
            return null;
        }
        String gender = (String) mapIn.get("gender");
        Double weightBalance = (Double) mapIn.get("weightBalance");
        String extendValue = (String) mapIn.get("extendValue");

        switch (type) {
        case 1: {
            // 身高
            if (StringUtils.isBlank(gender) || MapUtils.isEmpty(jsonMap)) {
                return null;
            }
            mapOut = getHeightWeightData(mapIn);
            break;
        }
        case 2: {
            // 体重
            if (StringUtils.isBlank(gender) || MapUtils.isEmpty(jsonMap)) {
                return null;
            }
            mapOut = getHeightWeightData(mapIn);
            break;
        }
        case 3: {
            // 腰围
            if (StringUtils.isBlank(gender) || StringUtils.isBlank(value) || StringUtils.isBlank(extendValue)) {
                return null;
            }
            mapOut = getWaistData(mapIn);
            break;
        }
        case 4: {
            // 胸围
            if (StringUtils.isBlank(gender) || MapUtils.isEmpty(jsonMap)) {
                return null;
            }
            mapOut = getChestData(mapIn);
            break;
        }
        case 5: {
            // 舒张压
            if (MapUtils.isEmpty(jsonMap)) {
                return null;
            }
            mapIn.put("bloodType", Constants.PHYSICAL_TYPE_FOR_BLOOD_DIASTOLIC);
            mapOut = getBloodPressureData(mapIn);
            break;
        }
        case 6: {
            // 收缩压
            if (MapUtils.isEmpty(jsonMap)) {
                return null;
            }
            mapIn.put("bloodType", Constants.PHYSICAL_TYPE_FOR_BLOOD_SYSTOLIC);
            mapOut = getBloodPressureData(mapIn);
            break;
        }
        case 7: {
            // 上臀部皮褶厚度
            break;
        }
        case 8: {
            // 肩胛部皮褶厚度
            break;
        }
        case 9: {
            // 腰(腹)部部皮褶厚度
            mapOut = getWaistSkinData(mapIn);
            break;
        }
        case 10: {
            // 上臂围
            mapOut = getUpArmLenData(mapIn);
            break;
        }
        case 11: {
            // 骨骼肌
            if (StringUtils.isBlank(gender) || null == weightBalance) {
                return null;
            }
            mapOut = getSkeletalMuscleData(mapIn);
            break;
        }
        case 12: {
            // 体脂百分比
            if (StringUtils.isBlank(gender)) {
                return null;
            }
            mapOut = getBodyFatPercentData(mapIn);
            break;
        }
        case 13: {
            // 体脂肪
            if (StringUtils.isBlank(gender) || null == weightBalance) {
                return null;
            }
            mapOut = getBodyFatData(mapIn);
            break;
        }
        }

        return mapOut;
    }

    /**
     * 生成带普通二维码文件流
     *
     * @return
     * @throws IOException
     */
    public static byte[] createQrCode(String content) throws IOException {

        ByteArrayOutputStream out = null;
        ByteArrayOutputStream logoQRcode = new ByteArrayOutputStream();
        try {
            out = new ByteArrayOutputStream();
            BufferedImage bim = getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, 300, 300, getDecodeHintType());
            // ImageIO.write(bim, "jpeg", file);
            ImageIO.write(bim, "jpeg", out);
            return out.toByteArray();
        } catch (Throwable e) {
            logger.error("生成二维码文件报错", e);
            ;
            throw new AppException("1200111", "生成二维码失败");
        } finally {
            if (null != out) {
                out.close();
            }
            if (null != logoQRcode) {
                logoQRcode.close();
            }
        }
    }

    /**
     * 生成带logo二维码文件流
     *
     * @return
     * @throws IOException
     */
    public static byte[] createQrCodeAndLogo(String content, String logoUrl) throws IOException {

        ByteArrayOutputStream out = null;
        ByteArrayInputStream in = null;
        ByteArrayOutputStream logoQRcode = new ByteArrayOutputStream();
        try {
            out = new ByteArrayOutputStream();
            BufferedImage bim = getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, 300, 300, getDecodeHintType());
            // ImageIO.write(bim, "jpeg", file);
            ImageIO.write(bim, "jpeg", out);
            // zp.addLogo_QRCode(out, new File("D:/logo.png"), new
            // LogoConfig());
            in = new ByteArrayInputStream(out.toByteArray());

            addLogo_QRCode(in, new URL(logoUrl), new LogoConfig(), logoQRcode);

            return logoQRcode.toByteArray();
        } catch (Throwable e) {
            logger.error("生成二维码文件报错", e);
            ;
            throw new AppException("1200111", "生成二维码失败");
        } finally {
            if (null != in) {
                in.close();
            }
            if (null != out) {
                out.close();
            }
            if (null != logoQRcode) {
                logoQRcode.close();
            }
        }

    }

    /**
     * 给二维码图片添加Logo 返回输出流
     *
     * @param logoPic
     */
    public static void addLogo_QRCode(InputStream in, URL logoPic, LogoConfig logoConfig, ByteArrayOutputStream out) {
        try {
            // ByteArrayOutputStream out = new ByteArrayOutputStream();
            if (null == in) {
                logger.error("file not find !");
                throw new AppException("1200111", "logo图标不存在");
            }
            /**
             * 读取二维码图片，并构建绘图对象
             */
            BufferedImage image = ImageIO.read(in);
            Graphics2D g = image.createGraphics();

            /**
             * 读取Logo图片
             */
            BufferedImage logo = ImageIO.read(logoPic);
            /**
             * 设置logo的大小,本人设置为二维码图片的20%,因为过大会盖掉二维码
             */
            int widthLogo = logo.getWidth(null) > image.getWidth() * 2 / 10 ? (image.getWidth() * 2 / 10)
                    : logo.getWidth(null),
                    heightLogo = logo.getHeight(null) > image.getHeight() * 2 / 10 ? (image.getHeight() * 2 / 10)
                            : logo.getHeight(null);
            // 计算图片放置位置
            /**
             * logo放在中心
             */
            int x = (image.getWidth() - widthLogo) / 2;
            int y = (image.getHeight() - heightLogo) / 2;
            /**
             * logo放在右下角
             */
            /*
             * int x = (image.getWidth() - widthLogo); int y =
             * (image.getHeight() - heightLogo);
             */
            // 开始绘制图片
            g.drawImage(logo, x, y, widthLogo, heightLogo, null);
            g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);
            g.setStroke(new BasicStroke(logoConfig.getBorder()));
            g.setColor(logoConfig.getBorderColor());
            g.drawRect(x, y, widthLogo, heightLogo);

            g.dispose();
            logo.flush();
            image.flush();
            // ImageIO.write(image, "png", new File("D:/"/*+new
            // Date().getTime()*/+"test.png"));
            ImageIO.write(image, "png", out);
        } catch (Exception e) {
            logger.error("生成二维码输出流报错", e);
            ;
            e.printStackTrace();
        }

    }

    public static List<String> parseStringToList(String oriStr) {
        List<String> list = new ArrayList<>();
        if (null == oriStr) {
            return list;
        }
        if (StringUtils.isNotBlank(oriStr) && oriStr.length() > 1) {

            String strArr[] = oriStr.split(Constants.COMMA_SPLIT_STR);
            for (String str : strArr) {
                if (StringUtils.isNotBlank(str)) {
                    list.add(str);
                }
            }
        }

        return list;
    }

    /**
     * 给二维码图片添加Logo
     *
     * @param qrPic
     * @param logoPic
     */
    public void addLogo_QRCode(File qrPic, File logoPic, LogoConfig logoConfig) {
        try {
            if (!qrPic.isFile() || !logoPic.isFile()) {
                logger.error("file not find !");
                throw new AppException("1200113", "生成二维码失败");
            }

            /**
             * 读取二维码图片，并构建绘图对象
             */
            BufferedImage image = ImageIO.read(qrPic);
            Graphics2D g = image.createGraphics();

            /**
             * 读取Logo图片
             */
            BufferedImage logo = ImageIO.read(logoPic);
            /**
             * 设置logo的大小,本人设置为二维码图片的20%,因为过大会盖掉二维码
             */
            int widthLogo = logo.getWidth(null) > image.getWidth() * 2 / 10 ? (image.getWidth() * 2 / 10)
                    : logo.getWidth(null),
                    heightLogo = logo.getHeight(null) > image.getHeight() * 2 / 10 ? (image.getHeight() * 2 / 10)
                            : logo.getHeight(null);

            // 计算图片放置位置
            /**
             *
             * logo放在中心
             */
            int x = (image.getWidth() - widthLogo) / 2;
            int y = (image.getHeight() - heightLogo) / 2;
            /**
             * logo放在右下角
             */
            /*
             * int x = (image.getWidth() - widthLogo); int y =
             * (image.getHeight() - heightLogo);
             */
            // 开始绘制图片
            g.drawImage(logo, x, y, widthLogo, heightLogo, null);
            g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);
            g.setStroke(new BasicStroke(logoConfig.getBorder()));
            g.setColor(logoConfig.getBorderColor());
            g.drawRect(x, y, widthLogo, heightLogo);

            g.dispose();
            logo.flush();
            image.flush();

            ImageIO.write(image, "png", new File("D:/"/*
                                                       * +new Date().getTime()
                                                       */
                    + "test.png"));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成二维码bufferedImage图片
     *
     * @param content
     *            编码内容
     * @param barcodeFormat
     *            编码类型
     * @param width
     *            图片宽度
     * @param height
     *            图片高度
     * @param hints
     *            设置参数
     * @return
     */
    public static BufferedImage getQR_CODEBufferedImage(String content, BarcodeFormat barcodeFormat, int width,
            int height, Map<EncodeHintType, ?> hints) {
        MultiFormatWriter multiFormatWriter = null;
        BitMatrix bm = null;
        BufferedImage image = null;
        try {
            multiFormatWriter = new MultiFormatWriter();

            // 参数顺序分别为：编码内容，编码类型，生成图片宽度，生成图片高度，设置参数
            bm = multiFormatWriter.encode(content, barcodeFormat, width, height, hints);

            bm = deleteWhite(bm);
            int w = bm.getWidth();
            int h = bm.getHeight();
            image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

            // 开始利用二维码数据创建Bitmap图片，分别设为白（0xFFFFFFFF）黑（0xFF000000）两色
            for (int x = 0; x < w; x++) {
                for (int y = 0; y < h; y++) {
                    image.setRGB(x, y, bm.get(x, y) ? 0xFF000000 : 0xFFCCDDEE);
                }
            }
        } catch (WriterException e) {
            e.printStackTrace();
        }
        return image;
    }

    // 删除二维码边框
    public static BitMatrix deleteWhite(BitMatrix matrix) {
        int[] rec = matrix.getEnclosingRectangle();
        int resWidth = rec[2] + 1;
        int resHeight = rec[3] + 1;

        BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
        resMatrix.clear();
        for (int i = 0; i < resWidth; i++) {
            for (int j = 0; j < resHeight; j++) {
                if (matrix.get(i + rec[0], j + rec[1]))
                    resMatrix.set(i, j);
            }
        }
        return resMatrix;
    }

    /**
     * 设置二维码的格式参数
     *
     * @return
     */
    public static Map<EncodeHintType, Object> getDecodeHintType() {
        // 用于设置QR二维码参数
        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        // 设置QR二维码的纠错级别（H为最高级别）具体级别信息
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 设置编码方式
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.MARGIN, 0);
        hints.put(EncodeHintType.MAX_SIZE, 350);
        hints.put(EncodeHintType.MIN_SIZE, 100);

        return hints;
    }

    /**
     * 验证是否为手机号
     *
     * @param phoneNo
     *            手机号
     * @return wuyz
     */
    public static boolean checkPhoneNo(String phoneNo) {
        Pattern pattern = Pattern.compile("^1[\\d]{10}");
        Matcher matcher = pattern.matcher(phoneNo);
        return matcher.matches();
    }

    // 短信发送接口
    /*
     * public static void sendALISms(String phoneNo, Object object, String
     * smsType) throws Exception {
     *
     * IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou",
     * "KxOYldlzgNbV7LPk", "Do7wFceam0fGLK3ovbJd2J2rZQRyUh");
     * DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Sms",
     * "sms.aliyuncs.com"); IAcsClient client = new DefaultAcsClient(profile);
     * SingleSendSmsRequest request = new SingleSendSmsRequest(); String
     * templateCode="SMS_33810202"; if(smsType.equals("02")){
     * templateCode="SMS_33910139"; } try { request.setSignName("贝生医疗");
     * request.setTemplateCode(templateCode);
     * request.setParamString("{\"code\":\""+context+"\"}");
     * request.setRecNum(phoneNo); SingleSendSmsResponse httpResponse =
     * client.getAcsResponse(request); //System.out.println("ss"); } catch
     * (ServerException e) { e.printStackTrace(); } catch (ClientException e) {
     * e.printStackTrace(); }
     *
     * }
     */

    // 阿里注册短信
    public static Boolean sendALISms(String phoneNo, String context, String smsType) throws Exception {
        Boolean flag = false;
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", "KxOYldlzgNbV7LPk",
                "Do7wFceam0fGLK3ovbJd2J2rZQRyUh");
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Sms", "sms.aliyuncs.com");
        IAcsClient client = new DefaultAcsClient(profile);
        SingleSendSmsRequest request = new SingleSendSmsRequest();
        String templateCode = "SMS_33810202"; // 注册
        if (smsType.equals("02")) {
            templateCode = "SMS_33910139"; // 找回密码
        } else if (smsType.equals("07")) {
            templateCode = "SMS_67255538"; // 提现
        }

        try {
            request.setSignName("贝生医疗");
            request.setTemplateCode(templateCode);
            request.setParamString("{\"code\":\"" + context + "\"}");
            request.setRecNum(phoneNo);
            SingleSendSmsResponse httpResponse = client.getAcsResponse(request);
            if (httpResponse != null) {
                if (httpResponse.getRequestId() != null) {
                    flag = true;
                } else {
                    flag = false;
                }
            } else {
                flag = false;
            }
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return flag;
    }

    // 阿里注册短信 (新api)
    public static Boolean sendALISmsNew(String phoneNo, String context, String smsType) throws Exception {
        Boolean flag = false;
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", "KxOYldlzgNbV7LPk",
                "Do7wFceam0fGLK3ovbJd2J2rZQRyUh");

        final String product = "Dysmsapi";//短信API产品名称（短信产品名固定，无需修改）
        final String domain = "dysmsapi.aliyuncs.com";//短信API产品域名（接口地址固定，无需修改）

        DefaultProfile.addEndpoint("cn-hangzhou","cn-hangzhou",product,domain);
        IAcsClient client = new DefaultAcsClient(profile);
        SendSmsRequest request = new SendSmsRequest();

        String templateCode = "SMS_33810202"; // 注册
        if (smsType.equals("02")) {
            templateCode = "SMS_33910139"; // 找回密码
        } else if (smsType.equals("07")) {
            templateCode = "SMS_67255538"; // 提现
        }

        try {
            request.setSignName("贝生医疗");
            request.setTemplateCode(templateCode);
            request.setTemplateParam("{\"code\":\"" + context + "\"}");
            request.setPhoneNumbers(phoneNo);
            SendSmsResponse httpResponse = client.getAcsResponse(request);
            if (httpResponse != null) {
            	logger.info("aliyun smssend back-->"+httpResponse.getCode()+"--"+httpResponse.getMessage());
                if (httpResponse.getRequestId() != null) {
                    flag = true;
                } else {
                    flag = false;
                }
            } else {
                flag = false;
            }
        } catch (Exception e) {
        	logger.error("aliyun smssend error",e);
        }
        return flag;
    }

    // 亿美软通短信-通知类
    public static int sendYMsms(String phoneNo, String context) throws Exception {
        String sn = "8SDK-EMY-6699-RFQPN";// 软件序列号,请通过亿美销售人员获取
        String key = "192329";// 序列号首次激活时自己设定
        // String password = "192329";// 密码,请通过亿美销售人员获取
        String baseUrl = "http://hprpt2.eucp.b2m.cn:8080/sdkproxy/";
        String param = "";
        String message = "【贝生医疗】" + context;
        message = URLEncoder.encode(message, "UTF-8");
        long seqId = System.currentTimeMillis();
        param = "cdkey=" + sn + "&password=" + key + "&phone=" + phoneNo + "&message=" + message + "&seqid=" + seqId;
        String url = baseUrl + "sendsms.action";
        String ret = "";
        try {
            ret = SDKHttpClient.sendSMS(url, param);
        } catch (Exception ex) {
            logger.error("调用外部亿美软通短信接口失败:", ex);
            ret = ErrorCode.EXCEPTION_TYPE_SYSTEM_OUTSMS_SERVICE_CALL_EXCP;// 失败
        }
        System.out.println("发送结果:" + ret);
        return Integer.parseInt(ret);
    }

    // 亿美软通短信-通知类
    public static int sendYMsms2(String phoneNo, String context) throws Exception {
        String sn = "8SDK-EMY-6699-RFQPN";// 软件序列号,请通过亿美销售人员获取
        String key = "192329";// 序列号首次激活时自己设定
        // String password = "192329";// 密码,请通过亿美销售人员获取
        String baseUrl = "http://hprpt2.eucp.b2m.cn:8080/sdkproxy/";
        String param = "";
        String message = context;
        message = URLEncoder.encode(message, "UTF-8");
        long seqId = System.currentTimeMillis();// 获取当前系统时间
        param = "cdkey=" + sn + "&password=" + key + "&phone=" + phoneNo + "&message=" + message + "&seqid=" + seqId;
        String url = baseUrl + "sendsms.action";
        // System.out.println("短信即将发送请注意:" + seqId);
        String ret = "";
        try {
            ret = SDKHttpClient.sendSMS(url, param);
        } catch (Exception ex) {
            logger.error("调用外部亿美软通短信接口失败:", ex);
            ret = ErrorCode.EXCEPTION_TYPE_SYSTEM_OUTSMS_SERVICE_CALL_EXCP;// 失败
        }
        // System.out.println("发送结果:" + ret);
        return Integer.parseInt(ret);
    }

    public static int sendYMsms3(String phoneNo, String context) throws Exception {
        String sn = "6SDK-EMY-6666-RHWLN";// 软件序列号,请通过亿美销售人员获取
        String key = "203969";// 序列号首次激活时自己设定
        // String password = "203969";// 密码,请通过亿美销售人员获取
        String baseUrl = "http://sdktaows.eucp.b2m.cn:8080/sdkproxy/";
        String param = "";
        context = URLEncoder.encode(context, "UTF-8");
        long seqId = System.currentTimeMillis();
        param = "cdkey=" + sn + "&password=" + key + "&phone=" + phoneNo + "&message=" + context + "&seqid=" + seqId;
        String url = baseUrl + "sendsms.action";

        // String ret = SDKHttpClient.registAndLogout(url, param);
        String ret = "";
        try {
            ret = SDKHttpClient.sendSMS(url, param);
        } catch (Exception ex) {
            logger.error("调用外部亿美软通短信接口失败:", ex);
            ret = ErrorCode.EXCEPTION_TYPE_SYSTEM_OUTSMS_SERVICE_CALL_EXCP;// 失败
        }
        System.out.println(param);
        System.out.println("发送结果:" + ret);
        return Integer.parseInt(ret);
    }

    /**
     * 产生随机码
     *
     * @param num
     *            多少位随机码
     * @return
     *
     * @version 1.0.0
     */
    public static String getRandom(int num) {
        Random random = new Random();
        StringBuffer str = new StringBuffer();
        for (int i = 0; i < num; i++) {
            str.append(Math.abs(random.nextInt() % 10));
        }

        return str.toString();
    }

    // 获取openId
    public static String getOpenId(String code) throws Exception {
        String msg = "";
        String openId = null;
        URL url = null;
        HttpURLConnection connection = null;
        OutputStream os = null;
        DataOutputStream dos = null;
        InputStream is = null;
        DataInputStream dis = null;
        String sdUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
        try {
            url = new URL(sdUrl);
            trustAllHttpsCertificates();
            connection = (HttpsURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            connection.setRequestProperty("Proxy-Connection", "Keep-Alive");
            connection.setDoOutput(true);
            connection.setDoInput(true);

            logger.info(sdUrl + "appid=" + Constants.appid + "&secret=" + Constants.appsecret + "&code=" + code
                    + "&grant_type=authorization_code");

            os = connection.getOutputStream();
            dos = new DataOutputStream(os);
            dos.write(("appid=" + Constants.appid + "&secret=" + Constants.appsecret + "&code=" + code
                    + "&grant_type=authorization_code").getBytes("UTF-8"));
            dos.flush();
            is = connection.getInputStream();
            dis = new DataInputStream(is);
            byte d[] = new byte[dis.available()];
            dis.read(d);
            String rs = new String(d, "UTF-8");
            if (rs != null) {
                logger.info("return message = " + rs);
                msg = rs;
                JSONObject jsObject = JSONObject.fromObject(msg);
                if (jsObject.containsKey("openid")) {
                    openId = jsObject.getString("openid");
                    logger.info("openId:" + openId);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dos != null) {
                try {
                    dos.close();
                } catch (IOException e) {
                }
            }

            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }

            if (dis != null) {
                try {
                    dis.close();
                } catch (IOException e) {
                }
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }

            if (connection != null) {
                connection.disconnect();
            }
        }
        return openId;
    }

    // 获取openId
    public static String getWechatInf(String sdUrl, String json) throws Exception {
        logger.info(sdUrl + "--" + json);
        String msg = "";
        URL url = null;
        HttpURLConnection connection = null;
        OutputStream os = null;
        DataOutputStream dos = null;
        InputStream is = null;
        DataInputStream dis = null;
        try {
            url = new URL(sdUrl);
            trustAllHttpsCertificates();
            connection = (HttpsURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
            connection.setRequestProperty("Proxy-Connection", "Keep-Alive");
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setConnectTimeout(30000);
            connection.setReadTimeout(30000);
            // System.setProperty("sun.net.client.defaultConnectTimeout",
            // "30000");// 连接超时30秒
            // System.setProperty("sun.net.client.defaultReadTimeout", "30000");
            // // 读取超时30秒

            os = connection.getOutputStream();
            if (!StringUtils.isEmpty(json)) {
                os.write(json.getBytes("UTF-8"));// 传入参数
            }
            dos = new DataOutputStream(os);
            dos.flush();
            is = connection.getInputStream();
            dis = new DataInputStream(is);
            byte d[] = new byte[dis.available()];
            dis.read(d);
            String rs = new String(d, "UTF-8");
            if (rs != null) {
                logger.info("return message = " + rs);
                msg = rs;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dos != null) {
                try {
                    dos.close();
                } catch (IOException e) {
                }
            }

            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }

            if (dis != null) {
                try {
                    dis.close();
                } catch (IOException e) {
                }
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }

            if (connection != null) {
                connection.disconnect();
            }
        }
        return msg;
    }

    public static void trustAllHttpsCertificates() throws Exception {
        javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
        javax.net.ssl.TrustManager tm = new miTM();
        trustAllCerts[0] = tm;
        javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    static class miTM implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
                throws java.security.cert.CertificateException {
            return;
        }

        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
                throws java.security.cert.CertificateException {
            return;
        }
    }

    public static Map<String, Object> appadd(String a, com.alibaba.fastjson.JSONObject jsonTow) {
        // System.out.println(a);
        // System.out.println(jsonTow);
        JSONObject node1 = JSONObject.fromObject(a);
        Iterator<?> it = node1.keys();
        Map<String, Object> map = new HashMap<String, Object>();
        while (it.hasNext()) {
            String key = it.next().toString();
            map.put(node1.getString(key), jsonTow.getString(key));
        }
        // System.out.println("111111111111111111111111111111111111111111" +
        // map.toString());
        return map;
    }

    // 将json串转换陈map
    public static Map<String, Object> mapTojson(String a) {
        // System.out.println(a);
        JSONObject node1 = JSONObject.fromObject(a);
        Iterator<?> it = node1.keys();
        Map<String, Object> map = new HashMap<String, Object>();
        while (it.hasNext()) {
            String key = it.next().toString();
            map.put(key, node1.getString(key));
        }
        // System.out.println("mapTojson : " + map.toString());
        return map;
    }

    /**
     * 处理问卷模板实现增删改
     *
     * @author wuyz
     * @param map
     *            入参信息
     * @return String 返回json串
     *
     **/
    public static String changeJson(Map<String, Object> map) {
        String str = map.get("TemplData").toString();// 个人问卷模板json串
        String str1 = map.get("questions").toString();// 需要操作的模板json串
        String code = map.get("code").toString();// 操作类型
        JSONArray node11 = JSONArray.fromObject(str);
        JSONObject node12 = JSONObject.fromObject(node11.getJSONObject(0));
        JSONArray node13 = node12.getJSONArray("children");
        JSONArray node14 = JSONArray.fromObject(str1);
        if (code.equals(Constants.HANDLE_TYPE_CHANGE)) {// 修改
            for (int i = 0; i < node13.size(); i++) {
                JSONObject job = node13.getJSONObject(i); // 遍历 jsonarray
                                                          // 数组，把每一个对象转成 json
                                                          // 对象
                for (int j = 0; j < node14.size(); j++) {
                    JSONObject job1 = node14.getJSONObject(j);
                    // System.out.println(i + ":" + job.get("id"));
                    if (job.get("id") != null && job.get("id").equals(job1.get("id"))) {
                        // System.out.println(job.get("id"));
                        node13.set(i, job1);
                    }
                }

            }
            node12.put("children", node13);
            node11.set(0, node12);
            // System.out.println(node11.toString());
        } else if (code.equals(Constants.HANDLE_TYPE_ADD)) {// 增加
            for (int i = 0; i < node14.size(); i++) {
                JSONObject job = node14.getJSONObject(i); // 遍历 jsonarray
                                                          // 数组，把每一个对象转成 json
                                                          // 对象
                for (int j = 0; j < node13.size(); j++) {
                    JSONObject job1 = node13.getJSONObject(j);
                    // 去除已经存在的数据
                    if (job.get("id") != null && job.get("id").equals(job1.get("id"))) {
                        System.out.println(job.get("id"));
                        break;
                    } else if (j == node13.size() - 1) {
                        node13.add(job);
                    }
                }

            }
            node12.put("children", node13);
            node11.set(0, node12);
            // System.out.println(node11.toString());

        } else if (code.equals(Constants.HANDLE_TYPE_DELETE)) {// 删除
            // System.out.println("11111111111" + node13.toString());
            for (int i = 0; i < node13.size(); i++) {
                JSONObject job = node13.getJSONObject(i); // 遍历 jsonarray
                                                          // 数组，把每一个对象转成 json
                                                          // 对象
                // System.out.println(i + ":" + job.get("id"));
                for (int j = 0; j < node14.size(); j++) {
                    JSONObject job1 = node14.getJSONObject(j);
                    if (job.get("id") != null && job.get("id").equals(job1.get("id"))) {
                        // System.out.println(job.get("id"));
                        node13.remove(i);
                        i--;
                    }
                }

            }
            node12.put("children", node13);
            node11.set(0, node12);
            // System.out.println(node11.toString());
        } else {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_QUEUE_NOT_EXIST, "无此操作类型，请联系统管理员！"));
        }
        return node11.toString();
    }

    /**
     * 处理出参实现数据匹配
     *
     * @author wuyz
     * @param jsonStr
     *            模板json串，map 数据集合
     * @return String 返回json串
     *
     **/
    public static JSONArray matching(String jsonStr, HashMap<String, Object> map) {
        if (map == null || map.size() <= 0) {
            return null;
        }
        JSONArray node11 = JSONArray.fromObject(jsonStr);
        JSONObject node12 = JSONObject.fromObject(node11.getJSONObject(0));
        JSONArray node13 = node12.getJSONArray("children");
        Set<String> keys = map.keySet();
        for (int i = 0; i < node13.size(); i++) {
            JSONObject job = node13.getJSONObject(i); // 遍历 jsonarray数组，把每一个对象转成
            // 匹配对应的key
            for (String key : keys) {
                if (job.containsValue(key)) {
                    job.put("checked", "0");
                    node13.set(i, job);
                    break;
                } else {
                    job.put("checked", "1");
                    node13.set(i, job);
                }
            }

        }
        node12.put("children", node13);
        node11.set(0, node12);
        // System.out.println(node11.toString());
        return node11;
    }

    /**
     * md5加密函数 入参参数描述：
     *
     * @param sourceStr
     *            String 需要加密的字符串
     * @param flag
     *            int 需要加密的位数：（1）32：返回32位加密串 （2）16：返回16位加密串 返回参数：
     * @return sourceStr String MD5加密后的字符串
     * @createTime 2017.06.13
     * @author wuyz
     *
     **/

    public static String MD5Encrept(String sourceStr, int flag) throws Exception {
        String result = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(sourceStr.getBytes());
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            if (flag == 32) {
                result = buf.toString();
            } else {
                result = buf.toString().substring(8, 24);
            }
            //// System.out.println("MD5(" + sourceStr + ",32) = " + result);
            //// System.out.println("MD5(" + sourceStr + ",16) = " +
            //// buf.toString().substring(8, 24));
        } catch (NoSuchAlgorithmException e) {
            throw new NoSuchAlgorithmException(e.toString());
        }

        return result;
    }

    /**
     * utf-8编码格式转换 输入参数：
     *
     * @param sourceStr
     *            String 需要转换的GBK的字符串 输出参数
     * @author wuyz
     * @createTime 2017.06.13
     **/
    public static String getUTF8XMLString(String sourceStr) throws Exception {
        StringBuffer sb = new StringBuffer();
        sb.append(sourceStr);
        String xmString = "";
        String xmlUTF8 = "";
        try {
            xmString = new String(sb.toString().getBytes("UTF-8"));
            xmlUTF8 = URLEncoder.encode(xmString, "UTF-8");
            // System.out.println("utf-8 编码：" + xmlUTF8) ;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return xmlUTF8;
    }

    /**
     * SHA-256 和 SHA-512j加密 输入参数：
     *
     * @param strText
     *            String 需要加密的字符串
     * @param strType
     *            String SHA-256 和 SHA-512 两种 Hash 算法 输出参数
     * @return  加密后的出参
     *            String 异或运算后的字符串
     * @author wuyz
     * @throws UnsupportedEncodingException
     * @throws Exception
     * @createTime 2017.06.13
     **/
    public static String changeToSHA(String strText, String strType) throws UnsupportedEncodingException {

        // 返回值
        String strResult = "";

        // 是否是有效字符串
        if (strText != null && strText.length() > 0) {
            try {
                // SHA 加密开始
                // 创建加密对象 并傳入加密類型
                MessageDigest messageDigest = MessageDigest.getInstance(strType);
                // 传入要加密的字符串
                messageDigest.update(strText.getBytes("UTF-8"));
                // 得到 byte 类型结果
                byte byteBuffer[] = messageDigest.digest();
                BASE64Encoder encode = new BASE64Encoder();
                strResult = encode.encode(byteBuffer);
                /*
                 * // 將 byte 转换 string StringBuffer strHexString = new
                 * StringBuffer(); // 遍历byte buffer for (int i = 0; i <
                 * byteBuffer.length; i++) { String hex =
                 * Integer.toHexString(0xff & byteBuffer[i]); if (hex.length()
                 * == 1) { strHexString.append('0'); } strHexString.append(hex);
                 * } // 得到返回結果 strResult = strHexString.toString();
                 */
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
        // System.out.println(strResult);
        strResult = strResult.toLowerCase();
        return strResult;
    }

    /**
     * 字符串间的异或运算 输入参数：
     *
     * @param StrOne
     *            String 进行异或运算字符串
     * @param StrTow
     *            String 进行异或运算字符串 输出参数
     * @return xorstr
     *            String 异或运算后的字符串
     * @author wuyz
     * @throws Exception
     * @createTime 2017.06.13
     **/
    public static String twoStringXor(String StrOne, String StrTow) throws Exception {
        // 运算时计算长度以StrTow和StrOne值中字符长度短的为准
        byte b1[] = StrOne.getBytes("UTF-8");
        ;
        byte b2[] = StrTow.getBytes("UTF-8");
        ;
        // 定义一个BASE64Encoder
        BASE64Encoder encode = new BASE64Encoder();
        // 将byte[]转换为base64
        // 新建一个BASE64Decoder
        // BASE64Decoder decode = new BASE64Decoder();
        byte longbytes[], shortbytes[];
        if (b1.length >= b2.length) {
            longbytes = b1;
            shortbytes = b2;
        } else {
            longbytes = b2;
            shortbytes = b1;
        }
        byte xorstr[] = new byte[shortbytes.length];
        int i = 0;
        for (; i < shortbytes.length; i++) {
            xorstr[i] = (byte) ((int) shortbytes[i] ^ (int) longbytes[i]);
        }

        /*
         * for (;i<longbytes.length;i++){ xorstr[i] = longbytes[i]; }
         */
        String base64 = encode.encode(xorstr);
        return base64;
    }

    /**
     * xml解析函数，转换成map 入参参数描述：
     *
     * @param Str
     *            String xml字符串 返回参数：
     * @return map Map 放回map
     * @createTime 2017.06.22
     * @author wuyz
     **/
    public static List<Map<String, Object>> FormatXml(String Str) throws Exception {
        // 将xml转换成map
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        try {
            // 将xml格式字符串转化为DOM对象
            org.dom4j.Document document = DocumentHelper.parseText(Str);
            // 获取根结点对象
            Element rootElement = document.getRootElement();
            // 循环根节点，获取其子节点
            int in = 0;
            for (Iterator<?> iter = rootElement.elementIterator(); iter.hasNext();) {
                Element element = (Element) iter.next(); // 获取标签对象
                // 获取该标签对象的属性
                // System.out.println(element);
                List<?> attr = element.attributes();
                Map<String, Object> map = new HashMap<String, Object>();
                // 取标签属性值
                for (int i = 0; i < attr.size(); i++) {
                    Attribute attrid = (Attribute) attr.get(i);
                    String attrVal = attrid.getValue();
                    String attrName = attrid.getName();
                    map.put(attrName, attrVal);
                }
                // 循环第一层节点，获取其子节点
                // 取标签间的值
                for (Iterator<?> iterInner = element.elementIterator(); iterInner.hasNext();) {
                    // 获取标签对象
                    Element elementOption = (Element) iterInner.next();
                    // 获取该标签对象的名称
                    String tagName = elementOption.getName();
                    // 获取该标签对象的内容
                    String tagContent = elementOption.getTextTrim();
                    // 输出内容
                    map.put(tagName, tagContent);
                }
                // 定义一个list
                list.add(in, map);
                in++;
                // System.out.println();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    // 数字校验
    public static boolean isNumeric(String str) {
        if (null == str) {
            return false;
        }
        Pattern pattern = Pattern.compile("([0-9]+\\.?[0-9]+)|([1-9]\\d*)");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }

    // 日期转星期
    public static Map<String, Object> dateToWeek(String datetime) {
        Map<String, Object> dateMap = new HashMap<String, Object>();
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance(); // 获得一个日历
        Date datet = null;
        try {
            datet = f.parse(datetime);
            cal.setTime(datet);
        } catch (ParseException e) {
            throw (new AppException(ErrorCode.FOLLOWUP_EXCEPTION_TYPE_DATE_PARSE_ERROR, "时间解析错误，格式不正确！"));
        }
        int kk = cal.get(Calendar.DAY_OF_WEEK);
        int w = kk - 1; // 指示一个星期中的某天
        if (w < 0)
            w = 0;
        dateMap.put("dayIndex", w);
        dateMap.put("weekStr", Constants.dayOfWeek[w]);

        return dateMap;
    }

    // 根据随访任务时间和门诊排班，计算下次随访时间
    public static List<String> calcNextDate(Map<String, Object> pIn) {
        String beginTime = (String) pIn.get("beginTime");
        String endTime = (String) pIn.get("endTime");
        String scheduleType = (String) pIn.get("scheduleType");
        List<String> outList = new ArrayList<String>();

        List<Map<String, Object>> scheduleList = typeCast(pIn.get("scheduleList"));
        if (!CollectionUtils.isEmpty(scheduleList)) {
            Map<String, Object> dateMap = new HashMap<String, Object>();
            Map<String, Object> schMap = new HashMap<String, Object>();
            String timeStr = beginTime;
            int dayIndex = 0;
            String weekStr = "";
            String workDay = "";
            int workPeriod = 0;
            int scize = scheduleList.size();
            int st = 0;
            for (; timeStr.compareTo(endTime) <= 0;) {
                if (Constants.DEPT_OUTPATIENT_SCHEDULE_WEEKLY.equals(scheduleType)) {
                    // 按周排班
                    dateMap = dateToWeek(timeStr);
                    dayIndex = (Integer) dateMap.get("dayIndex");
                    weekStr = (String) dateMap.get("weekStr");
                    for (st = 0; st < scize; st++) {
                        schMap = scheduleList.get(st);
                        workDay = (String) schMap.get("workDay");
                        workPeriod = Integer.parseInt("" + schMap.get("workPeriod"));

                        if (workDay.equals("" + dayIndex)) {
                            StringBuffer scheduleStr = new StringBuffer();
                            scheduleStr.append(timeStr);
                            scheduleStr.append(Constants.COLON_SPLIT_STR);
                            scheduleStr.append(weekStr);
                            scheduleStr.append(Constants.timeOfDay[workPeriod]);
                            outList.add(scheduleStr.toString());
                        }
                    }

                    timeStr = DateUtil.calcDay2(timeStr, "+", 1);
                } else if (Constants.DEPT_OUTPATIENT_SCHEDULE_MONTHLY.equals(scheduleType)) {
                    // 按月排班
                } else if (Constants.DEPT_OUTPATIENT_SCHEDULE_DATE.equals(scheduleType)) {
                    // 按具体日期排班
                }
            }
        }

        return outList;
    }

    /**
     * 将字符串转换成Map结构
     *
     * @param str
     *            需要转换的字符串
     * @return Map结构数据
     * @throws ParseException
     */
    public static Map<String, Object> stringToMap(String str) {
        Map<String, Object> map = new HashMap<String, Object>();
        str = str.replaceAll("\\s*", "");
        ;
        if (str.startsWith("{"))
            str = str.substring(1, str.length());
        if (str.endsWith("}"))
            str = str.substring(0, str.length() - 1);
        String[] datas = str.split(",");
        for (String data : datas) {
            String[] d = data.split("=");
            if (d.length == 2) {
                map.put(d[0], d[1]);
            } else {
                int index = data.indexOf("=");
                if (index > 0)
                    map.put(data.substring(0, index), data.substring(index + 1, data.length()));
            }
        }
        return map;
    }

    // 根据生日计算年龄
    /**
     * 年龄格式：小于三个月的显示几周几天，小于1岁的显示几月龄几天，大于一岁的显示几岁几月龄， 大于六岁的只显示岁。对于孕周小于37周的
     *
     * @param birthday
     * @return
     * @throws ParseException
     */
    public static String getCommAgeByBirthday(String testTime, String birthday) throws ParseException {
        StringBuilder builder = new StringBuilder();
        Calendar now = Calendar.getInstance();
        now.setTime(DateUtil.getDate_8(testTime));

        Calendar cal = Calendar.getInstance();
        // int age = 0;
        if (!now.getTime().before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            int week = 0;
            // 暂时展示 一个单位 岁、或月、周、天

            if (year >= 6) {
                builder.append(year).append("岁");
            } else {
                if (year >= 1) {
                    builder.append(year).append("岁");
                    if (month > 0) {
                        builder.append(month).append("月龄");
                    }
                }

                if (year < 1) {
                    if (year == 0 && month >= 3) {
                        builder.append(month).append("月龄");
                        if (day > 0) {
                            builder.append(day).append("天");
                        }
                    } else {
                        if (day > 0 || month > 0) {
                            day = (int) ((DateUtil.getDate_8(testTime).getTime()
                                    - DateUtil.getDate_8(birthday).getTime()) / 24 / 3600 / 1000);
                            week = day / 7;
                            builder.append(week).append("周");
                            int dayRemaid = day % 7;
                            if (dayRemaid > 0) {
                                builder.append(dayRemaid).append("天");
                            }
                        } else {
                            builder.append(day).append("天");
                        }
                    }
                }
            }
        } else {
            builder.append("0").append("天");
        }
        return builder.toString();
    }

    // 计算年龄 到月
    public static int getAgeMonthByBirthday(String testTime, String birthday) throws ParseException {
        Calendar now = Calendar.getInstance();
        now.setTime(DateUtil.getDate_8(testTime));

        int ageMonth = 0;
        Calendar cal = Calendar.getInstance();
        // int age = 0;
        if (!now.getTime().before(DateUtil.getDate_8(birthday))) {
            int yearNow = now.get(Calendar.YEAR);
            int monthNow = now.get(Calendar.MONTH);
            int dayOfMonthNow = now.get(Calendar.DAY_OF_MONTH);

            cal.setTime(DateUtil.getDate_8(birthday));
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH);
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int day = dayOfMonthNow - dayOfMonthBirth;
            int month = monthNow - monthBirth;
            int year = yearNow - yearBirth;

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }

            if (year > 0) {
                ageMonth += 12 * year;
            }
            if (month > 0) {
                ageMonth += month;
            }
        }
        return ageMonth;
    }

    // 宝宝月龄计算
    public static Map<String, Object> CalculateAgeOfMoon(Map<String, Object> map) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");// 小写的mm表示的是分钟
        // 宝宝月龄计算
        Calendar c = Calendar.getInstance();
        int day3 = 0;
        int month3 = 0;
        int year3 = 0;
        // 获取宝宝生日的年、月、日
        Date d = sdf.parse((String) map.get("birthday"));
        c.setTime(d);
        int year1 = c.get(Calendar.YEAR);
        int month1 = c.get(Calendar.MONTH) + 1;
        int day1 = c.get(Calendar.DAY_OF_MONTH);
        // 获取评估日期的年、月、日
        Date date = sdf.parse((String) map.get("createTime"));
        c.setTime(date);
        int year2 = c.get(Calendar.YEAR);
        int month2 = c.get(Calendar.MONTH) + 1;
        int day2 = c.get(Calendar.DAY_OF_MONTH);
        // 计算时间差
        if (day2 > day1 || day2 == day1) {
            // 创建日比出生日期的日大
            day3 = day2 - day1;
        } else {
            // 在创建日比出生日期的日小的情况下问月借1（一个月30天）
            if (month2 > month1) {
                // 创建月比出生日期月大
                day3 = day2 + 30 - day1;
                month2 = month2 - 1;
            } else {
                // 创建月比出生日期月小，需要从年份借1（一年12月）
                if (year2 > year1) {
                    day3 = day2 + 30 - day1;
                    month2 = month2 + 12 - 1;
                    year2 = year2 - 1;
                }
            }

        }
        // 创建月比出生日期月大
        if (month2 > month1) {
            month3 = month2 - month1;
        } else {
            // 创建月比出生日期月小，需要从年份借1（一年12月）
            if (year2 > year1) {
                month3 = month2 + 12 - month1;
                year2 = year2 - 1;
            }
        }
        if (year2 > year1) {
            year3 = year2 - year1;
        }
        map.clear();
        map.put("day3", day3);
        map.put("month3", month3);
        map.put("year3", year3);
        return map;

    }

    /**
     *
     * @Title: getXmlElementData
     * @Description: 解析xml获取子节点键值对
     * @return IData
     * @author: ht
     */
    public static Map<String, Object> getXmlElementData(String xmlStr) {
        Map<String, Object> data = new HashMap<String, Object>();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            org.w3c.dom.Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));

            org.w3c.dom.Element root = doc.getDocumentElement();
            NodeList nodeList = root.getChildNodes();
            if (nodeList != null) {
                getNodeList(nodeList, data);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     *
     * @Title: getNodeList
     * @Description: 获取子节点值
     * @param nodeList
     * @return IData
     * @author: ht
     */
    private static Map<String, Object> getNodeList(NodeList nodeList, Map<String, Object> data) {
        if (nodeList != null) {
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node childNode = nodeList.item(i);
                if (childNode.hasChildNodes()) {
                    getNodeList(childNode.getChildNodes(), data);
                } else {
                    data.put(childNode.getParentNode().getNodeName(), childNode.getNodeValue());
                }
            }
        }
        return data;
    }


    public static String getCellValue(Cell cell) {
        if (cell == null) {
            return "";
        }
        final int cellType = cell.getCellType();
        String strCellValue = "";
        switch (cellType) {
            case HSSFCell.CELL_TYPE_BLANK:
                strCellValue = "";
                break;
            case HSSFCell.CELL_TYPE_NUMERIC:
            	if (HSSFDateUtil.isCellDateFormatted(cell)) {
                    Date theDate = cell.getDateCellValue();
                    strCellValue = DateUtil.getDateA(theDate);
                } else {
                	//
                	strCellValue = String.valueOf(cell.getNumericCellValue());
                	if(!StringUtils.isEmpty(strCellValue)){
                		 if(strCellValue.indexOf(".") > 0){
             	        	strCellValue = strCellValue.replaceAll("0+?$", "");//去掉多余的0
             	        	strCellValue = strCellValue.replaceAll("[.]$", "");//如最后一位是.则去掉
             	        }
                	}
                }
                break;
            case HSSFCell.CELL_TYPE_STRING:
                strCellValue = cell.getRichStringCellValue().getString();
                break;
            case HSSFCell.CELL_TYPE_FORMULA:
            	 cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
            	 strCellValue = String.valueOf(cell.getNumericCellValue());
                 break;
            default:
                break;
        }

        return strCellValue.trim();
    }
    /**
     *
     * @Title: getParam
     * @Description: 获取请求参数集合
     * @param request
     * @return IData
     * @author: ht
     */
    public static Map<String, Object> getParam(HttpServletRequest request) {
        Map<String, Object> param = new HashMap<String, Object>();
        Enumeration<?> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String paramKey = (String) enu.nextElement();
            String value = request.getParameter(paramKey);
            // 中文转码
            try {
                value = new String(value.getBytes(Constants.ISO), Constants.UTF8);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            param.put(paramKey, value);
        }
        return param;
    }

    public static boolean isExcel2003(String filePath){
        return filePath.matches("^.+\\.(?i)(xls)$")|| filePath.matches("^.+\\.(?i)(csv)$");
    }

    public static boolean isExcel2007(String filePath){
        return filePath.matches("^.+\\.(?i)(xlsx)$") || filePath.matches("^.+\\.(?i)(xlsm)$");
    }

    /**
     * 字典排序
     *
     * @param timestamp
     * @param nonce
     * @param token
     * @return
     * @throws Exception
     */
    public static String getSignature(String timestamp, String nonce, String token) throws Exception {
        String maxString = "";// 排后面
        String minString = "";// 排前面
        if (timestamp.compareTo(nonce) < 0) {
            maxString = nonce;
            minString = timestamp;
        } else {
            maxString = timestamp;
            minString = nonce;
        }

        if (token.compareTo(maxString) > 0) {
            token = minString + maxString + token;
        } else if (token.compareTo(minString) < 0) {
            token = token + minString + maxString;
        } else {
            token = minString + token + maxString;
        }
        return SHA1Encode(token);
    }

    /**
     * SHA1Encode
     *
     * @todo //sha1加密
     * @param sourceString
     * @return String
     * @Exception
     * @update:
     */
    public static String SHA1Encode(String sourceString) {
        String resultString = null;
        try {
            resultString = new String(sourceString);
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            resultString = byte2hexString(md.digest(resultString.getBytes()));
        } catch (Exception ex) {
        }
        return resultString;
    }



    /**
     *
     * @Title: readStreamParameter
     * @Description: 从输入流读取post参数
     * @param in
     * @return String
     */
    public static String readStreamParameter(ServletInputStream in) {
        StringBuilder buffer = new StringBuilder();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(in, Constants.UTF8));
            String line = null;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != reader) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return buffer.toString();
    }


    //将问卷id转换成key：value格式  ，value包含题目的所有配置
    public static  Map<String,Object> tranferContentToMap(List<Object> contentList) {
  		Map<String,Object> contentMap = new HashMap<String,Object>();
  		for(int j =0,m=contentList.size();j<m;j++){
  			if(contentList.get(j) instanceof com.alibaba.fastjson.JSONArray){
  				com.alibaba.fastjson.JSONArray arr = (com.alibaba.fastjson.JSONArray)contentList.get(j);
  				for(int k =0;k<arr.size();k++){
  					com.alibaba.fastjson.JSONArray chirldArr = arr.getJSONObject(k).getJSONArray("children");
  					chirldJsonToMap(contentMap, chirldArr);
  				}
  			}else if(contentList.get(j) instanceof JSONObject){
  				com.alibaba.fastjson.JSONArray chirldArr = ((com.alibaba.fastjson.JSONObject)contentList.get(j)).getJSONArray("children");
  				/*for(int l = 0 ;l<chirldArr.size();l++){
  					if(!StringUtils.isEmpty(chirldArr.getJSONObject(l).getString("id"))){
  						contentMap.put(chirldArr.getJSONObject(l).getString("id"),chirldArr.getJSONObject(l));
  					}
  				}*/
  				chirldJsonToMap(contentMap, chirldArr);
  			}
  		}
  		return contentMap;
  	}

  	public static void chirldJsonToMap(Map<String, Object> contentMap,
  			com.alibaba.fastjson.JSONArray chirldArr) {
  		for(int l = 0 ;l<chirldArr.size();l++){
  			Object id = chirldArr.getJSONObject(l).getObject("id",Object.class);
  			if(!org.springframework.util.StringUtils.isEmpty(id)){
  				if(id instanceof String){
  					contentMap.put(id.toString(),chirldArr.getJSONObject(l));
  				}else if(id instanceof com.alibaba.fastjson.JSONArray){
  					com.alibaba.fastjson.JSONArray idArr = (com.alibaba.fastjson.JSONArray)id;
  					for(int n = 0 ;n< idArr.size() ; n++){
  						contentMap.put(idArr.getString(n),chirldArr.getJSONObject(l));
  					}
  				}
  			}else{
  				String relationId = chirldArr.getJSONObject(l).getString("relationId");
  				if(!StringUtils.isEmpty(relationId)){
  					com.alibaba.fastjson.JSONArray jsonArr = chirldArr.getJSONObject(l).getJSONArray("children");
  					if(null != jsonArr){
  						for(int n = 0;n<jsonArr.size();n++){
  							String chirldId = jsonArr.getJSONObject(n).getString("id");
  							if(!StringUtils.isEmpty(chirldId)){
  								contentMap.put(chirldId,jsonArr.getJSONObject(n));
  							}
  						}
  					}
  				}
  			}
  		}
  	}

	// 获取上传文件的远程路径
    public static String getUploadFilePath(String basicPathName, String folderName) {
        if (StringUtils.isBlank(basicPathName)) {
            return "";
        }
        String basicPath = PropertiesUtils.getProperty(basicPathName);
        if (StringUtils.isBlank(basicPath)) {
            return "";
        }
        StringBuffer pathBuff = new StringBuffer();
        pathBuff.append(basicPath);
        if (StringUtils.isNotBlank(folderName)) {
            pathBuff.append(folderName);
            pathBuff.append(Constants.DIVI_CHAR);
        }
        return pathBuff.toString();
    }


    //将阿拉伯数字转化成汉字
    public static String toChineseStr(int number) {
		String[] hanArr = { "零", "一", "二", "三", "四", "五", "六", "七","八", "九" };
		String[] unitArr = { "十", "百", "千", "万", "十万", "百万", "千万", "亿","十亿", "百亿", "千亿" };
		String numStr = number + "";
		String result = "";
		int numLen = numStr.length();
		for (int i = 0; i < numLen; i++) {
			int num = numStr.charAt(i) - 48;
			if (i != numLen - 1 && num != 0) {
				result += hanArr[num] + unitArr[numLen - 2 - i];
				if (number >= 10 && number < 20) {
					result = result.substring(1);
				}
			} else {
				if (!(number >= 10 && number % 10 == 0)) {
					result += hanArr[num];
				}
			}
		}
		return result;
	}


    //将中文转化成中文拼音
    public static String getEname(String name) throws BadHanyuPinyinOutputFormatCombination {
        HanyuPinyinOutputFormat pyFormat = new HanyuPinyinOutputFormat();
        pyFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        pyFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        pyFormat.setVCharType(HanyuPinyinVCharType.WITH_V);
        return PinyinHelper.toHanYuPinyinString(name, pyFormat, "", true);
    }

    //姓、名的第一个字母需要为大写
    public static String getUpEname(String name) throws BadHanyuPinyinOutputFormatCombination {
        char[] strs = name.toCharArray();
        String newname = null;

        //名字的长度
        if (strs.length == 2) {
                newname = toUpCase(getEname("" + strs[0])) + " "
                    + toUpCase(getEname("" + strs[1]));
        } else if (strs.length == 3) {
            newname = toUpCase(getEname("" + strs[0])) + " "
                    + toUpCase(getEname("" + strs[1] + strs[2]));
        } else if (strs.length == 4) {
            newname = toUpCase(getEname("" + strs[0] + strs[1])) + " "
                    + toUpCase(getEname("" + strs[2] + strs[3]));
        } else {
            newname = toUpCase(getEname(name));
        }

        return newname;
    }

    //首字母大写
    private static String toUpCase(String str) {
        StringBuffer newstr = new StringBuffer();
        newstr.append((str.substring(0, 1)).toUpperCase()).append(
                str.substring(1, str.length()));
        return newstr.toString();
    }

  //获取首字母
  	public static String getNameInitial (String name) throws BadHanyuPinyinOutputFormatCombination {
  		String nameOut = "";//返回首字母组成的字符串
  		//将姓名解析
  		char [] stringArr = name.toCharArray();
  		StringBuffer buf = new StringBuffer();//用户
  		for(int i=0;i<stringArr.length;i++) {
  			//获取当前字符的拼音
  			String namestr = getEname(String.valueOf(stringArr[i]));
  			if(!StringUtils.isBlank(namestr)) {
  				buf.append(namestr.substring(0, 1));
  			}
  		}
  		nameOut = buf.toString();
  		logger.info("nameOut  : "+nameOut);
        return nameOut;
  	}

  	 //是否早产
    public static boolean isPrematureBirth(String birthday, Integer pregnancyWeek) {
        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    	boolean flag = false;
        try {
            Date birthdayDate = DateUtil.getDate_8(birthday);

            Calendar now = Calendar.getInstance();
            Calendar cal = Calendar.getInstance();
            cal.setTime(birthdayDate);
            int year = now.get(Calendar.YEAR) - cal.get(Calendar.YEAR);
            int day = now.get(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH);
            int month = now.get(Calendar.MONTH) - cal.get(Calendar.MONTH);

            // 按照减法原理，先day相减，不够向month借；然后month相减，不够向year借；最后year相减。

            if (day < 0) {
                month -= 1;
                now.add(Calendar.MONTH, -1);// 得到上一个月，用来得到上个月的天数。
                day = day + now.getActualMaximum(Calendar.DAY_OF_MONTH);
            }
            if (month < 0) {
                month = (month + 12) % 12;
                year--;
            }
            if (null == pregnancyWeek || 0 == pregnancyWeek || pregnancyWeek >= 259
                    || (year >= 2 && month >= 0 && day >= 0)) { // 孕周大于37
                // 或者
                // 大于2岁
                // 按正常年龄算
            	flag = false;
            } else {
            	flag = true;
            }
        } catch (Exception e) {
        	logger.error("计算年龄报错", e);
        }
        return flag;
    }

    /**
     * 先进行MD5摘要再进行Base64编码获取摘要字符串
     *
     * @param str
     * @return
     */
    public static String base64AndMD5(String str) {
        if (str == null) {
            throw new IllegalArgumentException("入参为空");
        }
        return base64AndMD5(toBytes(str));
    }

    /**
     * 先进行MD5摘要再进行Base64编码获取摘要字符串
     *
     * @return
     */
    public static String base64AndMD5(byte[] bytes) {
        if (bytes == null) {
            throw new IllegalArgumentException("数组不可以为空");
        }
        try {
            final MessageDigest md = MessageDigest.getInstance("MD5");
            md.reset();
            md.update(bytes);
            final Base64 base64 = new Base64();
            final byte[] enbytes = base64.encode(md.digest());
            return new String(enbytes);
        } catch (final NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("无法进行MD5加密");
        }
    }

    /**
     * String转换为字节数组
     *
     * @param str
     * @return
     */
    private static byte[] toBytes(final String str) {
        if (str == null) {
            return null;
        }
        try {
            return str.getBytes(Constants.UTF8);
        } catch (final UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * List 转 String
     * @param mList
     * @return
     */
    public static String listToString(List<String> mList) {
        String convertedListStr = "";
        if (null != mList && mList.size() > 0) {
            String[] mListArray = mList.toArray(new String[mList.size()]);
            for (int i = 0; i < mListArray.length; i++) {
                if (i < mListArray.length - 1) {
                    convertedListStr += mListArray[i] + ",";
                } else {
                    convertedListStr += mListArray[i];
                }
            }
            return convertedListStr;
        } else return "List is null!!!";
    }


    /**
     * UTF-8编码转换为ISO-9959-1
     *
     * @param str
     * @return
     */
    public static String utf8ToIso88591(String str) {
        if (str == null) {
            return str;
        }

        try {
            return new String(str.getBytes("UTF-8"), "ISO-8859-1");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * ISO-9959-1编码转换为UTF-8
     *
     * @param str
     * @return
     */
    public static String iso88591ToUtf8(String str) {
        if (str == null) {
            return str;
        }

        try {
            return new String(str.getBytes("ISO-8859-1"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }


    /**
     * 计算签名
     *
     * @param secret APP密钥
     * @param method HttpMethod
     * @param path
     * @param headers
     * @param querys
     * @param bodys
     * @param signHeaderPrefixList 自定义参与签名Header前缀
     * @return 签名后的字符串
     */
    public static String sign(String secret, String method, String path,
    							Map<String, String> headers,
    							Map<String, String> querys,
    							Map<String, String> bodys,
    							List<String> signHeaderPrefixList) {
        try {
            Mac hmacSha256 = Mac.getInstance(Constants.HMAC_SHA256);
            byte[] keyBytes = secret.getBytes(Constants.UTF8);
            hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, Constants.HMAC_SHA256));

            return new String(Base64.encodeBase64(
                    hmacSha256.doFinal(buildStringToSign(method, path, headers, querys, bodys, signHeaderPrefixList)
                            .getBytes(Constants.UTF8))),
                    Constants.UTF8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 构建待签名字符串
     * @param method
     * @param path
     * @param headers
     * @param querys
     * @param bodys
     * @param signHeaderPrefixList
     * @return
     */
    private static String buildStringToSign(String method, String path,
    										Map<String, String> headers,
    										Map<String, String> querys,
    										Map<String, String> bodys,
                                            List<String> signHeaderPrefixList) {
        StringBuilder sb = new StringBuilder();

        sb.append(method.toUpperCase()).append(Constants.LF);
        if (null != headers) {
        	if (null != headers.get(Constants.HTTP_HEADER_ACCEPT)) {
                sb.append(headers.get(Constants.HTTP_HEADER_ACCEPT));
            }
        	sb.append(Constants.LF);
        	if (null != headers.get(Constants.HTTP_HEADER_CONTENT_MD5)) {
                sb.append(headers.get(Constants.HTTP_HEADER_CONTENT_MD5));
            }
            sb.append(Constants.LF);
            if (null != headers.get(Constants.HTTP_HEADER_CONTENT_TYPE)) {
                sb.append(headers.get(Constants.HTTP_HEADER_CONTENT_TYPE));
            }
            sb.append(Constants.LF);
            if (null != headers.get(Constants.HTTP_HEADER_DATE)) {
                sb.append(headers.get(Constants.HTTP_HEADER_DATE));
            }
        }
        sb.append(Constants.LF);
        sb.append(buildHeaders(headers, signHeaderPrefixList));
        sb.append(buildResource(path, querys, bodys));

        return sb.toString();
    }

    /**
     * 构建待签名Path+Query+BODY
     *
     * @param path
     * @param querys
     * @param bodys
     * @return 待签名
     */
    private static String buildResource(String path, Map<String, String> querys, Map<String, String> bodys) {
    	StringBuilder sb = new StringBuilder();

    	if (!StringUtils.isBlank(path)) {
    		sb.append(path);
        }
        Map<String, String> sortMap = new TreeMap<String, String>();
        if (null != querys) {
        	for (Map.Entry<String, String> query : querys.entrySet()) {
        		if (!StringUtils.isBlank(query.getKey())) {
        			sortMap.put(query.getKey(), query.getValue());
                }
        	}
        }

        if (null != bodys) {
        	for (Map.Entry<String, String> body : bodys.entrySet()) {
        		if (!StringUtils.isBlank(body.getKey())) {
        			sortMap.put(body.getKey(), body.getValue());
                }
        	}
        }

        StringBuilder sbParam = new StringBuilder();
        for (Map.Entry<String, String> item : sortMap.entrySet()) {
    		if (!StringUtils.isBlank(item.getKey())) {
    			if (0 < sbParam.length()) {
    				sbParam.append(Constants.SPE3);
    			}
    			sbParam.append(item.getKey());
    			if (!StringUtils.isBlank(item.getValue())) {
    				sbParam.append(Constants.SPE4).append(item.getValue());
    			}
            }
    	}
        if (0 < sbParam.length()) {
        	sb.append(Constants.SPE5);
        	sb.append(sbParam);
        }

        return sb.toString();
    }

    /**
     * 构建待签名Http头
     *
     * @param headers 请求中所有的Http头
     * @param signHeaderPrefixList 自定义参与签名Header前缀
     * @return 待签名Http头
     */
    private static String buildHeaders(Map<String, String> headers, List<String> signHeaderPrefixList) {
    	StringBuilder sb = new StringBuilder();

    	if (null != signHeaderPrefixList) {
    		signHeaderPrefixList.remove(Constants.X_CA_SIGNATURE);
    		signHeaderPrefixList.remove(Constants.HTTP_HEADER_ACCEPT);
    		signHeaderPrefixList.remove(Constants.HTTP_HEADER_CONTENT_MD5);
    		signHeaderPrefixList.remove(Constants.HTTP_HEADER_CONTENT_TYPE);
    		signHeaderPrefixList.remove(Constants.HTTP_HEADER_DATE);
    		Collections.sort(signHeaderPrefixList);
    		if (null != headers) {
    			Map<String, String> sortMap = new TreeMap<String, String>();
    			sortMap.putAll(headers);
    			StringBuilder signHeadersStringBuilder = new StringBuilder();
    			for (Map.Entry<String, String> header : sortMap.entrySet()) {
                    if (isHeaderToSign(header.getKey(), signHeaderPrefixList)) {
                    	sb.append(header.getKey());
                    	sb.append(Constants.COLON_SPLIT_STR);
                        if (!StringUtils.isBlank(header.getValue())) {
                        	sb.append(header.getValue());
                        }
                        sb.append(Constants.LF);
                        if (0 < signHeadersStringBuilder.length()) {
                        	signHeadersStringBuilder.append(Constants.COMMA_SPLIT_STR);
                        }
                        signHeadersStringBuilder.append(header.getKey());
                    }
                }
    			headers.put(Constants.X_CA_SIGNATURE_HEADERS, signHeadersStringBuilder.toString());
    		}
    	}

        return sb.toString();
    }

    /**
     * Http头是否参与签名 return
     */
    private static boolean isHeaderToSign(String headerName, List<String> signHeaderPrefixList) {
        if (StringUtils.isBlank(headerName)) {
            return false;
        }

        if (headerName.startsWith(Constants.CA_HEADER_TO_SIGN_PREFIX_SYSTEM)) {
            return true;
        }

        if (null != signHeaderPrefixList) {
            for (String signHeaderPrefix : signHeaderPrefixList) {
                if (headerName.equalsIgnoreCase(signHeaderPrefix)) {
                    return true;
                }
            }
        }

        return false;
    }

}

